home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / ANSI13L.ZIP / ANSI.ASM next >
Assembly Source File  |  1993-11-17  |  131KB  |  2,338 lines

  1. ;-----------------------------------------------------------------------------;
  2. ;  ANSI.COM - Replacement for the ANSI.SYS console device driver.             ;
  3. ;  Unlike ANSI.SYS which must be installed at boot time, ANSI.COM             ;
  4. ;  can be installed and uninstalled at anytime.  Enhancements include         ;
  5. ;  a fast screen write and variable sized keyboard reassignment buffer.       ;
  6. ;                                                                             ;
  7. ;  Update 3/2/89 - Fix for DOS function 0Bh, Check Standard Input Status      ;
  8. ;                      and STDIN in ANSI_INT_21 handler.                      ;
  9. ;                  Leading zero inserted for Device Status Report for         ;
  10. ;                      single digit cursor positions.                         ;
  11. ;                  INFORMATION typo 40 for 40H.                               ;
  12. ;                  WRITE_FAST modified to handle CR and LF instead of         ;
  13. ;                      WRITE_CHAR.                                            ;
  14. ;  Update 3/7/89 - Fix for CLS in graphics mode.                Version 1.2   ;
  15. ;                                                                             ;
  16. ;  Update 8/8/89 - STI added to INT 21 and 29 handler.          Version 1.3   ;
  17. ;:                                                                            ;
  18. ;: Update 01/01/90 - [KON | KOFF] and [PON | POFF] added        Version 1.31  ;
  19. ;:                   (all changes marked with ;: - Gary Meeker)               ;
  20. ;| Update 03/23/90 - /Q option added for no output when exectued        1.32  ;
  21. ;|                   (all changes marked with ;| - Gary Meeker)               ;
  22. ;; Update 05/16/90 - removed Syntax from output unless needed           1.33  ;
  23. ;;                   added /T test for load.                                  ;
  24. ;;                   (all changes marked with ;; - Gary Meeker)               ;
  25. ;. Update 10/28/90 - Added /P nn top of screen protection mode          1.34  ;
  26. ;.                   (all changes marked with ;. - Gary Meeker)               ;
  27. ;@ Update 12/01/90 - Added PCBoard @X## color code support              1.35  ;
  28. ;@                   also added @Variable@ Support                            ;
  29. ;@                   added /S to load stats data from file                    ;
  30. ;@                   (all changes marked with ;@ - Gary Meeker)               ;
  31. ;&                                                                            ;
  32. ;& Update 12/12/90 - My mistake, I didn't realize @X00 saved            1.36  ;
  33. ;&                   the color and @XFF restored it. Works now.               ;
  34. ;&                   Also made prompts return to start of line                ;
  35. ;&                   when cleared (like PCBoard does) & QON                   ;
  36. ;&                   now changes @MORE@ & @PAUSE@ into @WAIT@                 ;
  37. ;&                   (all changes marked with ;& - Gary Meeker)               ;
  38. ;                                                                             ;
  39. ;$ Update  4/22/91 - Change set cursor routine. If new position         1.37  ;
  40. ;$                   is off the screen use the last row or column.            ;
  41. ;$                   Added switch to not include PCB code.                    ;
  42. ;$                   Corrected syntax display.                                ;
  43. ;$                   Modified CLS to honor protected (/P) lines.              ;
  44. ;$                   Modified /T to returned status switches.                 ;
  45. ;$                   Modified /P to accept * to mean current row-1.           ;
  46. ;$                   (all changes marked with ;$ - Wayne Mingee)              ;
  47. ;                                                                             ;
  48. ;+ Update  9/19/91 - Allow ESC[p to clear all KB reassigns and          1.38  ;
  49. ;+                   ESC[np to clear single key reassign.                     ;
  50. ;+                   ie: ESC[65p will reset ascii 65 to it's default [A]      ;
  51. ;                                                                             ;
  52. ;^ Update 01/01/92 - Added XON/XOFF to control @X## color codes         1.39  ;
  53. ;^                   added support for finding relocated copies.              ;
  54. ;^                   This should allow LOADHI under DOS 5 or QRAM/QEMM        ;
  55. ;^                   (all changes marked with ;^ - Gary Meeker)               ;
  56. ;^                   (Was added to my 1.37 version 01/09/91 but now           ;
  57. ;^                   incorporated into this version as 1.39 to include        ;
  58. ;^                   changes by Wayne Mingee)                                 ;
  59. ;                                                                             ;
  60. ;~ Update 05/15/93 - Added additional support for PCBoard 15.0          1.3j  ;
  61. ;~                   @Variable:xxx@ and new variables.                        ;
  62. ;~                   (all changes marked with ;~ - Gary Meeker)               ;
  63. ;                                                                             ;
  64. ;` Update 06/06/93 - Fixed problem with (:nnR) Right & (:nnC) Center    1.3k  ;
  65. ;`                   justification when variable was full length and          ;
  66. ;`                   var needed no padding. Fixed delay which should          ;
  67. ;`                   have been in tenths of seconds not seconds.              ;
  68. ;`                   (fixes supplied by Chester Loving)                       ;
  69. ;                                                                             ;
  70. ;* Update 11/17/93 - Added additional support for PCBoard 15.1          1.3l  ;
  71. ;*                   Fixed problem using :nnx with Ratios.                    ;
  72. ;*                   (all changes marked with ;* - Gary Meeker)               ;
  73. ;                                                                             ;
  74. ;  PC Magazine - Michael J. Mefford                                           ;
  75. ;-----------------------------------------------------------------------------;
  76.  
  77. PCB            equ     0                     ;$ 1 = if PCB code wanted
  78.  
  79. _TEXT          SEGMENT PUBLIC 'CODE'
  80.                ASSUME  CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
  81.                ORG     100H
  82. START:         JMP     INITIALIZE
  83.  
  84. ;                 DATA AREA
  85. SIGNATURE      DB      CR,SPACE,SPACE,SPACE,CR,LF
  86. COPYRIGHT      DB      'ANSI 1.3l (C) 1988 Ziff Communications Co.',CR,LF  ;^;~;`
  87. PROGRAMMER     DB      'PC Magazine ',BOX,' Michael J. Mefford',CR,LF,LF,'$'
  88.                DB      CTRL_Z
  89.  
  90. CR             EQU     13
  91. LF             EQU     10
  92. CTRL_Z         EQU     26
  93. SPACE          EQU     32
  94. BOX            EQU     254
  95. ESC_CHAR       EQU     27
  96. SINGLE_QUOTE   EQU     39
  97. DOUBLE_QUOTE   EQU     34
  98. BELL           EQU     7
  99. BS             EQU     8
  100. TAB            EQU     9
  101.  
  102. OFF            EQU     1
  103. ON             EQU     2
  104. SLOW           EQU     4
  105. FAST           EQU     8
  106. KOFF           EQU     16                         ;:
  107. KON            EQU     32                         ;:
  108. POFF           EQU     64                         ;:
  109. PON            EQU     128                        ;:
  110. XOFF           EQU     256                        ;^
  111. XON            EQU     512                        ;^
  112. STATUS_MASK    EQU     1111110000000001B          ;: Set Mask and Bit
  113. AND_MASK       EQU     1111111111111100B          ;^ Set Mask
  114. OR_MASK        EQU     0000000000000001B          ;^ Set Bit
  115.  
  116. ANSI_STATE     DW      ESC_STATE
  117. STATUS         DW      ON OR FAST OR KON OR PON OR XON    ;: ;^
  118. PARAMETERS     DB      'OFF',0,'ON',0,0,'SLOWFASTKOFFKON',0,'POFFPON',0 ;:
  119.                DB      'XOFFXON',0                                      ;^
  120. LAST_PARAMETER EQU     $ - PARAMETERS
  121.  
  122. multiplex_id   db      0dbh                    ;^ Program ID for multiplex int
  123. dos_version    dw      0                       ;^ DOS Version number
  124. int2fh         dd      -1                      ;^ Int 2f vector (DOS MULTIPLEX)
  125. OLD_INT_29     DW      ?,?
  126. OLD_INT_16     DW      ?,?
  127. OLD_INT_21     DW      ?,?
  128. if PCB                                            ;$
  129. OLD_INT_08     DW      ?,?              ;@ Save Timer Interupt
  130. endif                                             ;$
  131. ATTRIBUTE      DB      7
  132. if PCB                                            ;$
  133. SAVE_ATTRIBUTE DB      ?                ;& For saving attribute
  134. endif                                             ;$
  135. SAVE_POSITION  DW      0
  136. LINE_WRAP      DB      ON
  137. QUOTE_TYPE     DB      ?
  138. ESC_COUNT      DW      0
  139. NUMBER_COUNT   DW      0
  140. if PCB                                            ;~
  141. IGNORE         DW      0                ;~ Count of characters to ignore
  142. JUSTIFY        DB      'L'              ;~ Justification - Default L
  143. ENV_FLAG       DW      0                ;*
  144. endif                                             ;~
  145.  
  146. COMMAND_TABLE  LABEL   BYTE
  147. DB   'H', 'A', 'B', 'C', 'D', 'f', 'n', 's', 'u', 'K', 'm', 'h', 'l', 'p', 'J'
  148. COMMAND_LENGTH EQU     $ - COMMAND_TABLE
  149.  
  150. DW   CURS_POSITION, CURSOR_UP,     CURSOR_DOWN, CURS_FORWARD, CURS_BACKWARD
  151. DW   HORZ_VERT_POS, DEVICE_STATUS, SAVE_CURSOR, RESTORE_CURS, ERASE_IN_LINE
  152. DW   SGR,           SET_MODE,      RESET_MODE,  REASSIGNMENT, CLS
  153. COMMAND_END    EQU     $ - 2
  154.  
  155. ATTRIBUTE_TABLE        LABEL    BYTE
  156. DB   00,01,04,05,07,08,30,31,32,33,34,35,36,37,40,41,42,43,44,45,46,47
  157. ATTRIBUTE_LENGTH       EQU      $ - ATTRIBUTE_TABLE
  158.  
  159. ;Format: AND mask,OR mask
  160. DB      000H,07H, 0FFH,08H, 0F8H,01H, 0FFH,80H, 0F8H,70H, 088H,00H
  161. DB      0F8H,00H, 0F8H,04H, 0F8H,02H, 0F8H,06H, 0F8H,01H, 0F8H,05H
  162. DB      0F8H,03H, 0F8H,07H, 08FH,00H, 08FH,40H, 08FH,20H, 08FH,60H
  163. DB      08FH,10H, 08FH,50H, 08FH,30H, 08FH,70H
  164. ATTRIBUTE_END          EQU      $ - 2
  165.  
  166. if PCB                                            ;$
  167. AT_VARIABLE_TABLE      LABEL BYTE                                          ;@
  168. DB   '@CLS@CLREOL@AUTOMORE@POFF@PON@QOFF@QON@BEEP@MORE@PAUSE@WAIT@HANGUP@' ;@
  169. DB   'DELAY@POS@'                                         ;~ For PCBoard 15.0
  170. DB   'ENV=@'                                              ;* For PCBoard 15.1
  171. DB   'OPTEXT@FIRSTU@FIRST@USER@CITY@HOMEPHONE@DATAPHONE@PROLTR@PRODESC@'   ;@
  172. DB   'EXPDATE@LASTDATEON@LASTTIMEON@INCONF@CONFNAME@BOARDNAME@'            ;@
  173. DB   'LASTCALLERNODE@LASTCALLERSYSTEM@EVENT@SYSOPIN@SYSOPOUT@BPS@NODE@'    ;@
  174. DB   'OFFHOURS@CARRIER@BICPS@RCPS@SCPS@'                    ;~ For PCBoard 15.0
  175. DB   'ALIAS@DIRNAME@LOGDATE@LOGTIME@NOCHAR@YESCHAR@PWXDATE@';* For PCBoard 15.1
  176. DB   'WHO@SYSDATE@SYSTIME@FILERATIO@BYTERATIO@'                         ;@ ;~
  177. DB   'RATIOBYTES@RATIOFILES@FILECREDIT@BYTECREDIT@'         ;* For PCBoard 15.1
  178. DB   'TIMELEFT@TIMELIMIT@TIMEUSED@TOTALTIME@'                              ;*
  179. DB   'CURMSGNUM@HIGHMSGNUM@LOWMSGNUM@LMR@'                                 ;*
  180. DB   'SECURITY@NUMCALLS@NUMTIMESON@'                                    ;@ ;*
  181. DB   'BYTESLEFT@BYTELIMIT@DLFILES@UPFILES@KBLEFT@KBLIMIT@CONFNUM@'         ;@
  182. DB   'MSGREAD@MSGLEFT@NUMBLT@NUMDIR@'                                   ;@ ;*
  183. DB   'DAYBYTES@MINLEFT@DLBYTES@UPBYTES@EXPDAYS@'                           ;@
  184. DB   'FREESPACE@RFILES@RBYTES@SFILES@SBYTES@'                           ;~ ;*
  185. DB   'DIRNUM@FBYTES@FFILES@FNUM@MAXFILES@MAXBYTES@'         ;* For PCBoard 15.1
  186. DB   'PWXDAYS@NUMCONF@'                                     ;* For PCBoard 15.1
  187.  
  188. LAST_VARIABLE          EQU     $ - 1                                       ;@
  189.  
  190. JUMP_TABLE             LABEL WORD                                          ;@
  191. DW      CLS, ERASE_IN_LINE, AUTOMORE, AUTOOFF, AUTOOFF, QOFF, QON        ;&;@
  192. DW      BEEP, MORE, PAUSE, WAIT1, SKIP_IT                                  ;@
  193. DW      DELAY_IT, POS_IT                                                   ;~
  194.  
  195. ACTION_CODES  EQU 14                   ;*;~ Length of Table
  196. STRING_CODES  EQU ACTION_CODES+36      ;*;~
  197. COMMA_CODES   EQU 14                   ;*   Start of Commas
  198.  
  199. SUB_TABLE              LABEL BYTE                                          ;@
  200. DB      25                                                                 ;*
  201. DB      8,15,15,25,24,13,13,1,47                                           ;@
  202. DB      8,8,5,33,13,63                                                     ;@
  203. DB      52,52,5,5,5,6,2                                                 ;~ ;@
  204. DB      12,6,6,6,6                                                      ;~ ;*
  205. DB      25,35,8,5,1,1,8                                                 ;~ ;*
  206. DB      255,0,0,4,4                                                     ;~ ;@
  207. DB      4,4,2,4                                                            ;*
  208. DB      2,2,2,2                                                            ;*
  209. DB      4,4,4,4                                                            ;*
  210. DB      2,4,2                                                           ;@ ;*
  211. DB      4,4,2,2,4,4,2                                                      ;@
  212. DB      4,4,2,2                                                         ;@ ;*
  213. DB      4,2,4,4,2                                                          ;@
  214. DB      4,2,4,2,4                                                       ;~ ;*
  215. DB      2,4,4,2,2,4                                                        ;*
  216. DB      2,2                                                                ;*
  217.  
  218. SUB_LIST               LABEL BYTE                      ;@
  219. DB     'Env_Data',17 DUP (0)                           ;* ENV=
  220. DB     '!OPTEXT!'                                      ;@ OPTTEXT
  221. DB     'GARY',0,0,0,0,0,0,0,0,0,0,0                    ;@ FirstU
  222. DB     'Gary',0,0,0,0,0,0,0,0,0,0,0                    ;@ First
  223. DB     'GARY MEEKER',0,0,0,0,0,0,0,0,0,0,0,0,0,0       ;@ User
  224. DB     'LAWRENCEVILLE, GA',0,0,0,0,0,0,0               ;@ City
  225. DB     '404 995-2699',0                                ;@ HomePhone
  226. DB     '404 962-1788',0                                ;@ DataPhone
  227. DB     'Z'                                             ;@ Proltr
  228. DB     'Zmodem       (Batch U/L and D/L)', 15 DUP (0)  ;@ ProDesc
  229.  
  230. DB     '01-01-91'                                      ;@ ExpDate
  231. DB     '12-01-90'                                      ;@ LastDateOn
  232. DB     '08:00'                                         ;@ LastTimeOn
  233. DB     'Sysop (19) Conference ',0,0,0,0,0,0,0,0,0,0,0  ;@ InConf
  234. DB     'Sysop',0,0,0,0,0,0,0,0                         ;@ ConfName
  235. DB     'SHARP Technical Support Line BBS', 31 DUP (0)  ;@ BoardName
  236.  
  237. DB     'MIKE BATE (RIVERDALE, GA)', 27 DUP (0)         ;@ LastCallerNode
  238. DB     'GARY MEEKER (LAWRENCEVILLE, GA)', 21 DUP (0)   ;@ LastCallerSystem
  239. DB     '04:30'                                         ;@ Event
  240. DB     '08:30'                                         ;@ SysopIn
  241. DB     '17:00'                                         ;@ SysopOut
  242. DB     '2400',0,0                                      ;@ bps           ;~
  243. DB     '1',0                                           ;@ Node
  244.  
  245. DB     '00:00-23:59',0                                 ;~ Offhours
  246. DB     '38400',0                                       ;~ Carrier
  247. DB     '3500',0,0                                      ;~ BICPS
  248. DB     '1700',0,0                                      ;~ RCPS
  249. DB     '1800',0,0                                      ;~ SCPS
  250.  
  251. DB     'ANSI PROGRAMMER', 10 DUP (0)                   ;* ALIAS
  252. DB     'PCBoard Utilities written by Sysop '           ;* DIRNAME
  253. DB     '11-15-93'                                      ;* LOGDATE
  254. DB     '01:30'                                         ;* LOGTIME
  255. DB     'N'                                             ;* NOCHAR
  256. DB     'Y'                                             ;* YESCHAR
  257. DB     '01-01-94'                                      ;* PWXDATE
  258.  
  259. DB     10,13                                           ;~ Who
  260. DB     ' (#)   Status                  User',10,13                              ;~
  261. DB     ' ---   ---------------------   -----------------------------',10,13     ;~
  262. DB     '   1   Available for CHAT      GARY MEEKER (LAWRENCEVILLE, GA)',10,13   ;~
  263. DB     '   2   No Caller this Node                                    ',10,13   ;~
  264. DB     26 DUP (0)                                      ;~
  265. ;* Ratios (no commas)
  266. DD          48                                         ;@ FileRatio
  267. DD         128                                         ;@ ByteRatio
  268. DD           5                                         ;* RatioBytes
  269. DD           3                                         ;* RatioFiles
  270. ;* No Commas in the following
  271. DW           1                                         ;* FileCredit
  272. DD        2048                                         ;* ByteCredit
  273.  
  274. DW          61                                      ;@ ;* timeleft
  275. DW         121                                      ;@ ;* timelimit
  276. DW          59                                      ;@ ;* timeused
  277. DW          59                                      ;@ ;* totaltime
  278.  
  279. DD        4734                                      ;@ ;* CurMsgNum
  280. DD        4745                                      ;@ ;* HighMsgNum
  281. DD        1002                                      ;@ ;* LowMsgNum
  282. DD        4700                                      ;~ ;* LMR
  283. ;* Commas start here.
  284. DW         120                                         ;@ Security
  285. DD       23946                                         ;@ numcalls
  286. DW        2107                                         ;@ numtimeson
  287.  
  288. DD     9508313                                         ;@ bytesleft
  289. DD    10238976                                         ;@ bytelimit
  290. DW          44                                         ;@ dlfiles
  291. DW        1234                                         ;@ upfiles
  292. DD        9285                                         ;@ KBLeft
  293. DD        9999                                         ;@ KBLimit
  294. DW          19                                         ;@ ConfNum
  295.  
  296. DD        3456                                         ;@ MsgRead
  297. DD         987                                         ;@ MsgLeft
  298. DW          20                                         ;@ NumBlt
  299. DW          31                                         ;@ NumDir
  300.  
  301. DD       30663                                         ;@ DayBytes
  302. DW          61                                         ;@ MinLeft
  303. DD      730663                                         ;@ DLBytes
  304. DD    12345678                                         ;@ UpBytes
  305. DW           0                                         ;@ ExpDays
  306.  
  307. DD    49356800                                         ;~ FreeSpace
  308. DW           8                                         ;~ RFiles
  309. DD      234567                                         ;~ RBytes
  310. DW          31                                         ;~ SFiles
  311. DD     3456789                                         ;~ SBytes
  312.  
  313. DW          29                                         ;* DirNum
  314. DD      876543                                         ;* FBytes
  315. DD           5                                         ;* FFiles
  316. DW           6                                         ;* FNum
  317. DW          30                                         ;* MaxFiles
  318. DD     2097152                                         ;* MaxBytes
  319. DW          90                                         ;* PWXDays
  320. DW         200                                         ;* NumConf
  321.  
  322. SUB_LENGTH     EQU      $ - SUB_LIST
  323.  
  324. PAUSE_TIMER    DW      182                             ;@
  325. PAUSE_DELAY    DW      182                             ;@ 10 Seconds
  326. MORE_DELAY     DW      182 * 12                        ;@ 2 Minute
  327. WAIT_DELAY     DW      182 * 12                        ;@ 2 Minute
  328.  
  329. WAIT_PROMPT    DB      'Press (Enter) to continue?'    ;@ ;*
  330. WAIT_LENGTH    DW      $ - WAIT_PROMPT                 ;@
  331. MORE_PROMPT    DB      '(61 min left), (H)elp, More?'  ;@
  332. MORE_LENGTH    DW      $ - MORE_PROMPT                 ;@
  333. COMMA          DB      0                               ;@
  334. Q_STATE        DB      0                               ;&
  335. endif                                             ;$
  336.  
  337. BIOS_ACTIVE_PAGE       EQU     62H
  338. ACTIVE_PAGE    DB      ?
  339. ADDR_6845      DW      ?
  340. BIOS_CRT_MODE          EQU     49H
  341. CRT_MODE       DB      ?
  342. CRT_COLS       DW      ?
  343. CRT_LEN        DW      ?
  344. CRT_START      DW      ?
  345. CRT_DATA_LENGTH        EQU     $ - CRT_MODE
  346. CURSOR_POSN    LABEL   WORD
  347. CURSOR_COL     DB      ?
  348. CURSOR_ROW     DB      ?
  349. CRT_ROWS       DB      ?
  350.  
  351. START_SCROLL   DB      0       ;. Number of rows to protect from scrolling up
  352.  
  353. DOS_INPUT      DB      OFF
  354. BUSY_FLAG      DB      OFF
  355. REASSIGN_FLAG  DB      OFF
  356. REMOVE_FLAG    DB      ON
  357. REASSIGN_COUNT DW      0
  358. REASSIGN_POS   DW      ?
  359. FUNCTION_16    DB      ?
  360. ZR             EQU     1000000B
  361.  
  362. ESC_BUFFER_SIZE      EQU     126
  363. REASSIGNMENT_DEFAULT EQU     200
  364. REASSIGNMENT_SIZE    DW      REASSIGNMENT_DEFAULT
  365. REASSIGNMENT_MAX     EQU     60 * 1024
  366. REASSIGN_END         DW      REASSIGNMENT_BUFFER
  367. BUFFER_END           DW      REASSIGNMENT_BUFFER + REASSIGNMENT_DEFAULT
  368.  
  369. ;                   CODE AREA
  370. ; ************* INTERRUPT HANDLERS ************* ;
  371. ;------------------------------------------------------------------------------;
  372. ; INT 29 is an undocumented interrupt called by DOS for output to the console. ;
  373. ;------------------------------------------------------------------------------;
  374.  
  375. ANSI_INT_29    PROC    FAR
  376.                STI
  377.                PUSH    AX                      ;Save all registers.
  378.                PUSH    BX
  379.                PUSH    CX
  380.                PUSH    DX
  381.                PUSH    SI
  382.                PUSH    DI
  383.                PUSH    DS
  384.                PUSH    ES
  385.                PUSH    BP
  386.  
  387.                CLD                             ;All string operations forward.
  388.                MOV     BX,CS                   ;Point to our data segment.
  389.                MOV     DS,BX
  390.                MOV     ES,BX
  391.                CALL    ANSI_STATE              ;Call the current state of
  392.                                                ; the ANSI Esc sequence.
  393.                POP     BP
  394.                POP     ES
  395.                POP     DS
  396.                POP     DI
  397.                POP     SI
  398.                POP     DX
  399.                POP     CX
  400.                POP     BX
  401.                POP     AX                      ;Restore all registers and
  402.                IRET                            ; and return
  403. ANSI_INT_29    ENDP
  404.  
  405. ;------------------------------------------------;
  406.  
  407. ANSI_INT_21    PROC    FAR
  408.                PUSHF
  409.                CMP     AH,0BH                  ;If DOS function 0Bh (Check
  410.                JNZ     CK_INPUT                ; Standard Input Status)
  411.                CMP     CS:REASSIGN_FLAG,ON     ; and reassignment in progress,
  412.                JNZ     CK_INPUT                ; including a Device Status
  413.                CALL    DWORD PTR CS:OLD_INT_21 ; Request, then process call in
  414.                MOV     AL,0FFH                 ; case control break pressed;
  415.                IRET                            ; then return 0FFh for char ready
  416.  
  417. CK_INPUT:      CMP     AH,3FH                  ;Read from STDIN?
  418.                JNZ     CK_CONSOLE
  419.                OR      BX,BX
  420.                JZ      INPUT
  421.  
  422. CK_CONSOLE:    CMP     AH,0AH                  ;If DOS Int 21 functions Ah,
  423.                JZ      INPUT                   ; 7h, 1h or console input (6h)
  424.                CMP     AH,7                    ; then tell INT 16, DOS input
  425.                JZ      INPUT                   ; is active.
  426.                CMP     AH,1
  427.                JZ      INPUT
  428.                CMP     AH,8
  429.                JZ      INPUT
  430.                CMP     AH,6
  431.                JNZ     QUICK21_EXIT
  432.                CMP     DL,0FFH
  433.                JZ      INPUT
  434. QUICK21_EXIT:  POPF                              ;If not, let the original
  435.                JMP     DWORD PTR CS:OLD_INT_21   ; interrupt process the call.
  436.  
  437. INPUT:         POPF
  438.                MOV     CS:DOS_INPUT,ON           ;INT 16 handler flag.
  439.                PUSHF
  440.                CALL    DWORD PTR CS:OLD_INT_21   ;Emulate an interrupt.
  441.                MOV     CS:DOS_INPUT,OFF          ;Turn flag back off.
  442.                STI
  443.                RET     2                         ;Return with current flags.
  444. ANSI_INT_21    ENDP
  445.  
  446. ;-----------------------------------------------------------------;
  447. ; If we get here via a DOS console input call, any awaiting key   ;
  448. ; in keyboard buffer is checked to see if it is to be reassigned. :
  449. ;-----------------------------------------------------------------;
  450.  
  451. ANSI_INT_16    PROC    FAR
  452.                STI                             ;Interrupts back on.
  453.                PUSHF                           ;Preserve flags on stack.
  454.                PUSH    BP
  455.                PUSH    DS
  456.                PUSH    AX
  457.                PUSH    CS                      ;Point to our data.
  458.                POP     DS
  459.  
  460.                CMP     DOS_INPUT,OFF           ;If not called via a DOS
  461.                JZ      QUICK16_EXIT            ; console input call, exit.
  462.                CMP     BUSY_FLAG,ON            ;If already processing a call,
  463.                JZ      QUICK16_EXIT            ; exit.
  464.                CLD                             ;All string operations forward.
  465.                MOV     BP,SP                   ;Base reference to flags on stack
  466.                MOV     FUNCTION_16,AH          ;Save function request.
  467.                AND     AH,NOT 10H              ;Strip possible extended request.
  468.                JZ      GET_KEY                 ;If zero, it's wait for a key.
  469.                DEC     AH                      ;Else, decrement.  If zero it's
  470.                JZ      KEY_STATUS              ; key status, else exit.
  471.  
  472. QUICK16_EXIT:  POP     AX                      ;Restore registers and let
  473.                POP     DS                      ; original interrupt handler
  474.                POP     BP                      ; process the call.
  475.                POPF
  476.                JMP     DWORD PTR CS:OLD_INT_16
  477.  
  478. KEY_STATUS:    OR      BYTE PTR [BP+6],ZR      ;Assume none ready; ZR = 1.
  479. GET_KEY:       MOV     BUSY_FLAG,ON            ;Non-reentrant; flag busy.
  480.                POP     AX
  481.                PUSH    BX                      ;Save some more registers.
  482.                PUSH    CX
  483.                PUSH    DX
  484.                PUSH    SI
  485.                PUSH    DI
  486.                CMP     REASSIGN_FLAG,ON        ;Already in process of reassign?
  487.                JZ      CK_BUFFER               ;If yes, check kbd buffer.
  488.  
  489.                PUSHF                           ;Else, emulate an interrupt.
  490.                CALL    DWORD PTR OLD_INT_16
  491.                PUSHF                           ;Status call results in flags.
  492.                TEST    FUNCTION_16,1           ;Was it a status call?
  493.                JZ      CK_DUP                  ;If no, check key returned.
  494.                POPF                            ;Else, retrieve status results.
  495.                JZ      INT16_EXIT              ;If zero, no key waiting.
  496.                AND     BYTE PTR [BP+6],NOT ZR  ;Else, ZR = 0.
  497.                PUSHF                           ;PUSHF just to keep stack right.
  498.  
  499. CK_DUP:        POPF                            ;Fix stack.
  500.                TEST    STATUS,KOFF             ;:If KOFF then we don't do
  501.                JNZ     INT16_EXIT              ;:re-assignments
  502.                MOV     BX,AX                   ;Match procedure wants key in BX.
  503.                CALL    CK_MATCH                ;Check reassignment buffer.
  504.                JC      INT16_EXIT              ;If no match, exit.
  505.                MOV     AX,[DI]                 ;Else, retrieve string length.
  506.                SUB     AX,3                    ;Adjust for length word and match
  507.                ADD     DI,3                    ; byte; same for string pointer.
  508.                OR      BL,BL                   ;Extended key? ie. key = 0.
  509.                JNZ     STORE_COUNT             ;If no, save length and pointer.
  510.                DEC     AX                      ;Else, adjust for extended code.
  511.                INC     DI
  512. STORE_COUNT:   MOV     REASSIGN_COUNT,AX       ;Save string length.
  513.                MOV     REASSIGN_POS,DI         ;Save pointer to string.
  514.                MOV     REASSIGN_FLAG,ON        ;Flag that replacement in effect.
  515. CK_BUFFER:     TEST    FUNCTION_16,1           ;Was it a key wait function call?
  516.                JNZ     RETRIEVE                ;If no, key status; get it.
  517.                CMP     REMOVE_FLAG,OFF         ;Removed it from kbd buffer?
  518.                JZ      RETRIEVE                ;If yes, get reassignment.
  519.                MOV     AH,FUNCTION_16          ;Else, eat the replaced character
  520.                INT     16H                     ; via INT 16.
  521.                MOV     REMOVE_FLAG,OFF         ;Flag character eaten.
  522.  
  523. RETRIEVE:      MOV     DI,REASSIGN_POS         ;Retrieve pointer to string.
  524.                MOV     AX,[DI]                 ;Retrieve replacement character.
  525.                TEST    FUNCTION_16,1           ;Is it a key wait function call?
  526.                JZ      REMOVE                  ;If yes, bump pointer up one.
  527.                AND     BYTE PTR [BP+6],NOT ZR  ;If no, status call; ZR = 0
  528.                JMP     SHORT INT16_EXIT        ;All done.
  529.  
  530. REMOVE:        INC     REASSIGN_POS            ;Move pointer to next character.
  531.                DEC     REASSIGN_COUNT          ;One less character to replace.
  532.                JZ      REASSIGN_DONE           ;If end of string, reset flags.
  533.                OR      AL,AL                   ;Else, extended replacement?
  534.                JNZ     INT16_EXIT              ;If no, done here.
  535.                INC     REASSIGN_POS            ;Else adjust pointers.
  536.                DEC     REASSIGN_COUNT
  537.                JNZ     INT16_EXIT              ;End of string?
  538. REASSIGN_DONE: MOV     REASSIGN_FLAG,OFF       ;If yes, reset flags.
  539.                MOV     REMOVE_FLAG,ON
  540.  
  541. INT16_EXIT:    MOV     BUSY_FLAG,OFF           ;Reset the busy flag.
  542.                POP     DI                      ;Restore registers.
  543.                POP     SI
  544.                POP     DX
  545.                POP     CX
  546.                POP     BX
  547.                POP     DS
  548.                POP     BP
  549.                POPF                            ;Flags on stack have status
  550.                RET     2                       ; results; kill old flags.
  551. ANSI_INT_16    ENDP
  552. if PCB                                            ;$
  553. ANSI_INT_08    PROC    FAR                      ;@
  554.                CMP     CS:[PAUSE_TIMER],0       ;@
  555.                JE      SKIP_TIMER               ;@
  556.                DEC     CS:[PAUSE_TIMER]         ;@
  557. SKIP_TIMER:    JMP     DWORD PTR CS:OLD_INT_08  ;@
  558. ANSI_INT_08    ENDP                             ;@
  559. endif                                             ;$
  560. ;^============================================================================
  561. ;^ MUXINT processes calls to interrupt 2Fh
  562. ;^ Entry:  AH - Device ID
  563. ;^ Exit:   AL - 0FFh if AH = Alias device ID. Unchanged otherwise.
  564. ;^         ES - Code segment if AH = Alias device ID. Unchanged otherwise.
  565. ;^============================================================================
  566. muxint         proc    far                     ;^
  567.                cmp     ah,cs:[multiplex_id]    ;^ Check for program ID
  568.                je      muxint_1                ;^ Its us, indicate installed.
  569.                jmp     cs:[int2fh]             ;^ else pass the call on
  570. muxint_1:                                      ;^
  571.                mov     al,-1                   ;^ Indicate Alias installed
  572.                push    cs                      ;^ ES = installed code segment
  573.                pop     es                      ;^
  574.                iret                            ;^
  575. muxint         endp                            ;^
  576.  
  577. ; ************* ANSI ESCAPE STATE ROUTINES ************* ;
  578.  
  579. ESC_STATE:     MOV     BX,OFFSET BRACKET_STATE ;Assume Esc character.
  580.                CMP     AL,ESC_CHAR             ;Is it Esc?  If yes, store
  581.                JZ      SHORT_JUMP              ; char. and next state.
  582. if PCB                                            ;$
  583.                CMP     DOS_INPUT,ON            ;@ Called via DOS Input?
  584.                JE      WRITE_CHAR2             ;@ Yes, Nevermind
  585.                MOV     BX,OFFSET ATX_STATE     ;@ No, Assume @ Character
  586.                CMP     AL,'@'                  ;@ Is it @? If yes, store
  587.                JZ      SHORT_JUMP              ;@ char. and next state.
  588. WRITE_CHAR2:
  589. endif                                             ;$
  590.                JMP     WRITE_CHAR              ;@ Else, normal char; write it.
  591. ;------------------------------------------------;
  592.  
  593. BRACKET_STATE: MOV     BX,OFFSET SPECIAL_STATE ;Assume left bracket.
  594.                CMP     AL,'['                  ;Is it left bracket?  If yes,
  595. SHORT_JUMP:    JZ      STORE_STATE             ;store char. and next state.
  596.                JMP     FLUSH_BUFFER            ;Else, flush Esc out of buffer.
  597.  
  598. ;---------------------------------------------------------------;
  599. ; Must process <ESC>[2J (CLS) regardless if ANSI.COM ON or OFF. ;
  600. ;---------------------------------------------------------------;
  601.  
  602. SPECIAL_STATE: MOV     BX,OFFSET CLS_STATE     ;Assume Erase in Display code.
  603.                CMP     AL,'2'                  ;Is it the '2' ?
  604.                JZ      STORE_STATE             ;If yes, progress to next state.
  605.                TEST    STATUS,OFF              ;Else, is ANSI OFF ?
  606.                JNZ     FLUSH_BUFFER            ;If yes, flush Esc, bracket.
  607.                MOV     BX,OFFSET PARAM_STATE   ;Else, check for first Set,
  608.                CMP     AL,'='                  ; Reset Mode characters of
  609.                JZ      STORE_STATE             ; '=' and '?'.
  610.                CMP     AL,'?'
  611.                JZ      STORE_STATE             ;If found, store.
  612.                JMP     SHORT DO_PARAMETER      ;Else, check other codes.
  613.  
  614. ;------------------------------------------------;
  615.  
  616. CLS_STATE:     CMP     AL,'J'                  ;Is it second character of CLS?
  617.                MOV     DI,OFFSET COMMAND_END   ;If yes, execute
  618.                JZ      EXECUTE                 ; Erase in Display procedure.
  619.                TEST    STATUS,OFF              ;ANSI OFF?  If yes, flush buffer.
  620.                JNZ     FLUSH_BUFFER            ; If not fall through to process.
  621.                MOV     BYTE PTR NUMBER_BUFFER,2 ;Store the previous 2.
  622. DO_PARAMETER:  MOV     ANSI_STATE,OFFSET PARAM_STATE  ;Parameter state.
  623.  
  624. ;------------------------------------------------;
  625.  
  626. PARAM_STATE:   CALL    CK_QUOTE                ;Is it single or double quotes?
  627.                JZ      STORE_STATE             ;If yes, store string state.
  628.                CMP     AL,';'                  ;Is it semi-colon delimiter?
  629.                JNZ     CK_NUMBER               ;If no, check if number.
  630.                INC     NUMBER_COUNT            ;Else, increment number count.
  631.                JMP     SHORT BUFFER_CHAR       ;Buffer the semi-colon.
  632.  
  633. CK_NUMBER:     CMP     AL,'0'                  ;Is it below 0 ?
  634.                JB      FLUSH_BUFFER            ;If yes, illegal; flush buffer.
  635.                CMP     AL,'9'                  ;Else, is it above 9 ?
  636.                JA      DO_COMMAND              ;If yes, check for command char.
  637.                CALL    ACCUMULATE              ;Else it's a number; accumulate.
  638.                JMP     SHORT BUFFER_CHAR       ;Buffer the character.
  639.  
  640. DO_COMMAND:    MOV     DI,OFFSET COMMAND_TABLE ;Point to legal ANSI commands.
  641.                MOV     CX,COMMAND_LENGTH       ;Number of commands.
  642.                REPNZ   SCASB                   ;Check for a match.
  643.                JNZ     FLUSH_BUFFER            ;If no match, flush sequence.
  644.                INC     NUMBER_COUNT            ;Else, increment for last number.
  645.                MOV     DI,OFFSET COMMAND_END   ;Point to appropriate command
  646.                SHL     CX,1                    ; processing procedure.
  647.                SUB     DI,CX
  648. EXECUTE:       CALL    GET_BIOS_DATA           ;Get cursor position data.
  649.                CALL    DS:[DI]                 ;Do command subroutine.
  650.                JMP     SHORT FLUSH_END         ;Clear buffer.
  651.  
  652. ;------------------------------------------------;
  653.  
  654. QUOTE_STATE:   CMP     AL,QUOTE_TYPE           ;Is it an ending string quote?
  655.                JNZ     BUFFER_CHAR             ;If no, buffer literal.
  656.                MOV     BX,OFFSET PARAM_STATE   ;Else, back to parameter parsing.
  657.  
  658. ;------------------------------------------------;
  659.  
  660. STORE_STATE:   MOV     ANSI_STATE,BX           ;Store the ANSI state.
  661.  
  662. ;------------------------------------------------;
  663.  
  664. BUFFER_CHAR:   MOV     DI,ESC_COUNT            ;Buffer the character in case
  665.                CMP     DI,ESC_BUFFER_SIZE      ; ending ANSI command is illegal.
  666.                JZ      FLUSH_BUFFER            ;If buffer full, flush.
  667.                ADD     DI,OFFSET ESC_BUFFER    ;Point to next buffer position.
  668.                STOSB                           ;Store the character.
  669.                INC     ESC_COUNT               ;Increment the sequence count.
  670.                RET
  671.  
  672. ;------------------------------------------------;
  673.  
  674. FLUSH_BUFFER:                                     ;$
  675. if PCB                                            ;$
  676.                CALL    BUFFER_CHAR             ;@ Buffer current character also!
  677. FLUSH_BUFF2:                                   ;@
  678. else                                              ;$
  679.                PUSH    AX                      ;Save the current character. Might need removal
  680. endif                                             ;$
  681.                MOV     SI,OFFSET ESC_BUFFER    ;Point to the sequence buffer.
  682.                MOV     CX,ESC_COUNT            ;Count of buffered characters.
  683. if pcb                                            ;~
  684. FLUSH_BUFF3:   PUSH    CX                      ;~
  685.                STC                             ;~Indicate LEFT PADDING
  686.                CALL    PAD_STRING              ;~
  687. endif                                             ;~
  688.  
  689. NEXT_FLUSH:    LODSB                           ;Retrieve one.
  690.                PUSH    CX                      ;Save counter and pointer.
  691.                PUSH    SI
  692.                CALL    WRITE_CHAR              ;Write character to screen.
  693.                POP     SI                      ;Restore counter and pointer.
  694.                POP     CX
  695.                LOOP    NEXT_FLUSH              ;Flush entire buffer.
  696. ife PCB                                           ;$
  697.                POP     AX                      ;@Retrieve last character.   Might need removal
  698.                CALL    WRITE_CHAR              ;@Write it also.             Might need removal
  699. endif                                             ;$
  700.  
  701. if PCB                                           ;~
  702.                POP     CX                      ;~
  703.                CLC                             ;~Indicate RIGHT PADDING
  704.                CALL    PAD_STRING              ;~
  705. endif                                            ;~
  706.  
  707. FLUSH_END:     XOR     AX,AX                         ;*
  708.                MOV     ESC_COUNT,AX                  ;* Reset counter.
  709.                MOV     ANSI_STATE,OFFSET ESC_STATE   ;Back to Esc state.
  710.                MOV     NUMBER_COUNT,AX               ;* Reset parameter counter.
  711. if PCB                                           ;*
  712.                MOV     ENV_FLAG,AX                   ;* Reset flag.
  713. endif                                            ;*
  714.                PUSH    CS                            ;Point to our data.
  715.                POP     ES
  716.                MOV     DI,OFFSET NUMBER_BUFFER       ;Clear number buffer
  717.                MOV     CX,ESC_BUFFER_SIZE / 2        ; to zeros.
  718.                REP     STOSW
  719.                RET
  720. if PCB                                            ;$
  721.  
  722. ;------------------------------------------------;@
  723. COLOR_STATE:   MOV     AH,AL                   ;^ Save character
  724.                CMP     AL,'0'                  ;@ Is it below 0 ?
  725.                JB      FLUSH_BUFFER            ;@ If yes, illegal; flush buffer.
  726.                CMP     AL,'9'                  ;@ Else, is it 0 - 9 ?
  727.                JBE     DO_COLOR                ;@ If yes, Make color.
  728.                CMP     AL,'A'                  ;@ Is it below A ?
  729.                JB      FLUSH_BUFFER            ;@ If yes, illegal; flush buffer.
  730.                CMP     AL,'F'                  ;@ Is it Above F ?
  731.                JA      FLUSH_BUFFER            ;@ If yes, illegal; flush buffer.
  732.                SUB     AL,7                    ;@ Else, adjust for Hex
  733. DO_COLOR:      CALL    ACCUM_COLOR             ;@ Accumulate Color.
  734.                MOV     AH,AL                   ;^ get saved character
  735.                INC     NUMBER_COUNT            ;@ Count the character
  736.                CMP     NUMBER_COUNT,2          ;@ Already got two?
  737.                JNE     SHORT BUFFER_CHAR   ;~;&;@ No, Buffer the character.
  738.                TEST    STATUS,OFF              ;@ Else, is ANSI OFF ?
  739.                JNZ     FLUSH_BUFFER            ;@ If yes, flush Esc, bracket.
  740.                TEST    STATUS,XOFF             ;^ Are @Xnn colors off?
  741.                JNZ     FLUSH_END               ;^ Yes, Ignore this completely
  742.                INC     CL                      ;& Is it @XFF restore code?
  743.                JNZ     COLOR_2                 ;& No,  Check for save code
  744.                MOV     CL,SAVE_ATTRIBUTE       ;& Yes, Get back saved attribute
  745.                JMP     SHORT COLOR_3           ;& and set it
  746. COLOR_2:       DEC     CL                      ;& Is it @X00 save code
  747.                JNZ     COLOR_3                 ;& No,  just set it then
  748.                MOV     CL,ATTRIBUTE            ;& Yes, Save the attribute
  749.                MOV     SAVE_ATTRIBUTE,CL       ;&
  750.                JMP     FLUSH_END               ;& and flush it
  751. COLOR_3:       MOV     ATTRIBUTE,CL            ;@ Set Attribute
  752.                JMP     FLUSH_END               ;@ Clear Buffer
  753.  
  754. ;------------------------------------------------;~
  755. POSITION_SUB:  CMP     AL,'@'                  ;~ Is it another @
  756.                JE      FOUND_END               ;~ Yes, so process it
  757.                CMP     AL,'0'                  ;~ No, is it Numeric?
  758.                JB      SHORT_FLUSH2            ;~ No, and invalid!
  759.                CMP     AL,'9'                  ;~ Maybe, let's see
  760.                JA      CHECK_TYPE              ;~ No, maybe a justification
  761.                CALL    ACCUMULATE              ;~ Build the number
  762.                JMP     SHORT BUFFER_IGNORE     ;~
  763. CHECK_TYPE:    MOV     AH,AL                   ;~ Copy it so we can Capitalize
  764.                AND     AH,0DFh                 ;~ Force Upper Case
  765.                CMP     AH,'C'                  ;~ Centered?
  766.                JE      POS_TYPE                ;~ Yes,
  767.                CMP     AH,'R'                  ;~ No, Right Justified?
  768.                JE      POS_TYPE                ;~     Yes,
  769. SHORT_FLUSH2:  MOV     IGNORE,0                ;~ No, So Zero out IGNORE!
  770.                JMP     SHORT_FLUSH             ;~     Invalid character
  771. POS_TYPE:      MOV     JUSTIFY, AH             ;~     Yes, Save the type
  772. BUFFER_IGNORE: INC     IGNORE                  ;~ We have to ignore these
  773. BUFFER_JUMP:   JMP     BUFFER_CHAR             ;~ But buffer the character also
  774.  
  775. ;------------------------------------------------;@
  776. VARIABLE_SUB:  CMP     AL,':'                  ;~ Is it a ':' instead of '@'
  777.                JNE     VARIABLE_2              ;~ No, continue
  778.                MOV     BYTE PTR NUMBER_BUFFER,0;~ Reset Variable
  779.                MOV     JUSTIFY,'L'             ;~ Reset justification to default
  780.                MOV     BX, OFFSET POSITION_SUB ;~ Yes, Redirect the ANSI_STATE
  781.                INC     IGNORE                  ;~ We need to ignore this
  782.                JMP     STORE_STATE             ;~ Store the state
  783. VARIABLE_2:                                    ;~
  784.                CMP     AL,'='                  ;* Is it a '=' instead of '@'
  785.                JNE     VARIABLE_3              ;* No, continue
  786.                MOV     BX,ESC_COUNT            ;* Yes, Indicate it
  787.                CMP     BX,4                    ;*  Is it Most likely ENV= ?
  788.                JNE     SHORT_FLUSH2            ;*  No, Flush it
  789.                MOV     ENV_FLAG,BX             ;*   else save the pointer
  790.                JMP     BUFFER_JUMP             ;* and Buffer it
  791. VARIABLE_3:                                    ;*
  792.                CMP     AL,'@'                  ;@ Is it another @
  793.                JE      FOUND_END               ;~ Yes, so process it
  794.                CMP     ENV_FLAG,0              ;* Are we Ignoring?
  795.                JNE     BUFFER_IGNORE           ;* Yes, buffer but inc ignore
  796.                JB      SHORT_FLUSH2            ;@ No, and not valid, so flush
  797.                CMP     AL,'Z'                  ;~ Is it UpperCase
  798.                JA      SHORT_FLUSH2            ;~ No, so flush
  799.                JMP     BUFFER_JUMP           ;&;@ No, Buffer the Char (indirect)
  800. FOUND_END:                                     ;~
  801.                MOV     DX,OFFSET AT_VARIABLE_TABLE ;@ Point to Variable List
  802.                XOR     BX,BX                   ;@ Position in Variable List
  803. NEXT_VARI:     MOV     DI,DX                   ;@ Load DI
  804.                INC     BX                      ;@ Count the Variable
  805.                MOV     SI,OFFSET ESC_BUFFER    ;@ Point to our Variable
  806.                MOV     CX,OFFSET LAST_VARIABLE ;@ Point to End of list
  807.                SUB     CX,DI                   ;@ Minus our current location
  808.                MOV     AL,'@'                  ;@ We need to start on these
  809.                REPNE   SCASB                   ;@ so find one
  810.                JCXZ    SHORT_FLUSH             ;@ End of List? Yes
  811.                MOV     DX,DI                   ;@ No,Save Variable list pointer
  812.                DEC     DI                      ;@ No, Back up to the @
  813.                MOV     CX,ESC_COUNT            ;@ Length of Variable
  814.                SUB     CX,IGNORE               ;~ But ignore the last few maybe
  815.                REP     CMPSB                   ;@ See if this one matches?
  816.                JNZ     NEXT_VARI               ;@ Didn't match that one!
  817.                CMP     [DI],AL                 ;@ Last Character has to be an @
  818.                JNZ     NEXT_VARI               ;@ Nope
  819.                DEC     BX                      ;@ Back up 1
  820.                CMP     BX,ACTION_CODES-1       ;@ Is it an Action code     ;~
  821.                JA      NOT_ACTION              ;@ No
  822.                SHL     BX,1                    ;@ BX x 2 for proper offset
  823.                MOV     DI,OFFSET JUMP_TABLE    ;@ Point to command table
  824.                ADD     DI,BX                   ;@ Adjust to the desired command
  825.                JMP     EXECUTE                 ;@ Execute the command
  826. NOT_ACTION:    MOV     SI, OFFSET SUB_TABLE    ;@ Point to Sub Table
  827.                MOV     AX,BX                   ;@ Save Variable Number
  828.                MOV     CX,BX                   ;@ Copy Variable Number
  829.                XOR     BX,BX                   ;@ Zero Offset
  830.                XOR     DX,DX                   ;@ Zero out initial length
  831.                SUB     CX,ACTION_CODES-1       ;@ Adjust Variable Number   ;~
  832. NEXT_OFFSET:   ADD     BX,DX                   ;@ Add last Length to Offset
  833.                MOV     DL,[SI]                 ;@ Get Length
  834.                INC     SI                      ;@ Bump the pointer
  835.                LOOP    NEXT_OFFSET             ;@ Do all of them
  836.                MOV     CX,DX                   ;@ Get last Length
  837.                MOV     SI,OFFSET SUB_LIST      ;@ Point to the substitue buffer.
  838.                ADD     SI,BX                   ;@ Add Offset
  839.                SUB     AX,STRING_CODES         ;@ Is It a String Variable ;~
  840.                JB      IS_STRING               ;@ Yes, Flush our Substitute
  841.                CMP     AX,1                    ;@ Is it Date ot Time?
  842.                JBE     IS_TIMEDATE             ;@ No, It's a Number
  843.                SUB     AX,2                    ;@ Adjust Variable number
  844.                CALL    NUMBER_PARSE            ;@ Create a Numeric value then
  845.                JMP     SHORT VAR_END           ;@ Flush our Number
  846. IS_TIMEDATE:   CALL    MAKE_TIMEDATE           ;@
  847. IS_STRING:     MOV     DI,SI                   ;@ Copy Pointer to DI for SCASB
  848.                MOV     AL,0                    ;@ We look for a Zero
  849.                REPNE   SCASB                   ;@ Findit it
  850.                JNE     GOT_END                 ;@ Skip if we didn't hit a Zero
  851.                DEC     DI                      ;@ Back up if we did
  852. GOT_END:       MOV     CX,DI                   ;@ Get Current Location
  853.                SUB     CX,SI                   ;@ Subtract Starting Location
  854. VAR_END:       JMP     FLUSH_BUFF3          ;~ ;@ Flush our Substitute
  855.  
  856. SHORT_FLUSH:   PUSH    AX                      ;& Save Character
  857.                CALL    FLUSH_BUFF2             ;@ Flush what we have now
  858.                POP     AX                      ;& Restore Character
  859.                JMP     ESC_STATE               ;& And save the new state
  860.  
  861. ;------------------------------------------------;~
  862. PAD_STRING:    PUSH    CX                      ;~ Save count
  863.                PUSH    SI                      ;~ Save Pointer
  864.                LAHF                            ;~ Save Carry in AH
  865.                CMP     IGNORE,0                ;~ Do we need to pad?
  866.                JE      NO_PAD                  ;~ No, nevermind
  867.                MOV     BL,BYTE PTR NUMBER_BUFFER ;~
  868.                XOR     BH,BH                   ;~ Get the length desired in BX
  869.                CMP     BX,CX                ;` ;~ Variable Longer or Same!?
  870.                JLE     NO_PAD               ;` ;~ Yes, nevermind
  871.                SUB     BX,CX                   ;~ We need this many spaces
  872.                XOR     BH,BH                   ;~ Keep it short
  873.                MOV     CX,BX                   ;~ We need it in CX
  874.                CMP     JUSTIFY,'R'             ;~ Right justification?
  875.                JNE     PAD_2                   ;~ No, Left or Center
  876.                SAHF                            ;~ Yes, Get Carry NC=RIGHT PAD
  877.                JNC     NO_PAD                  ;~ Nevermind, Were not doing it
  878.                JMP     SHORT DO_PAD            ;~ Pad it
  879. PAD_2:         CMP     JUSTIFY,'C'             ;~ Center justification?
  880.                JE      PAD_3                   ;~ Yes,
  881.                SAHF                            ;~ No, Must be Left (Default)
  882.                JC      NO_PAD                  ;~ Nevermind, Were not doing it
  883.                JMP     SHORT DO_PAD            ;~ Pad it
  884. PAD_3:         SHR     CX,1                    ;~ Centering Divide by 2
  885.                SAHF                            ;~ Yes, Get Carry NC=RIGHT PAD
  886.                JNC     DO_PAD                  ;~ OK, we are padding the RIGHT
  887.                SUB     BX,CX                   ;~ OK, we are padding the LEFT
  888.                MOV     CX,BX                   ;~     so use the remainder
  889. DO_PAD:        JCXZ    NO_PAD               ;` ;~ Nevermind, nothing to do!
  890.                CALL    POS_IT0              ;` ;~ So go write the spaces.
  891. NO_PAD:        POP     SI                      ;~ restore pointer
  892.                POP     CX                      ;~ restore count
  893.                RET                             ;~ and back we go.
  894.  
  895. ;------------------------------------------------;@
  896. ATX_STATE:     MOV     BX,OFFSET COLOR_STATE   ;@ Assume 'X' Character
  897.                CMP     AL,'X'                  ;@ Is it X? If yes, store
  898.                JZ      SHORT_STORE             ;@ char. and next state.
  899.                CMP     AL,'@'                  ;@ Is it another '@' already?
  900.                JZ      WRITE_CHAR              ;@ Yes!
  901.                CMP     AL,ESC_CHAR             ;& Is it an Escape
  902.                JE      SHORT_FLUSH             ;& Yes, so flush buffer & restart
  903.                MOV     BX,OFFSET VARIABLE_SUB  ;@ No, Must be a Variable
  904.                MOV     IGNORE,0                ;~ Reset IGNORE Count to Zero
  905. SHORT_STORE:   JMP     STORE_STATE             ;@ Store the state
  906. endif                                             ;$
  907. ;------------------------------------------------;
  908. ; Slow video writes are via BIOS Write TTY.      ;
  909. ;------------------------------------------------;
  910.  
  911. WRITE_CHAR:    CMP     AL,BELL                 ;Let BIOS process BS and BELL.
  912.                JZ      WRITE_TTY
  913.                CMP     AL,BS
  914.                JZ      WRITE_TTY
  915.  
  916.                CALL    GET_BIOS_DATA           ;Get BIOS video data.
  917.                CMP     AL,TAB                  ;Is character a TAB?
  918.                JNZ     CK_ACTIVE               ;If no, process normally.
  919.                MOV     CX,CURSOR_POSN          ;Else, expand TAB to
  920.                AND     CX,7                    ; appropriate space characters.
  921.                NEG     CX
  922.                ADD     CX,8
  923. NEXT_TAB:      PUSH    CX
  924.                MOV     AL,SPACE
  925.                CALL    CK_ACTIVE
  926.                POP     CX
  927.                LOOP    NEXT_TAB
  928.                RET
  929.  
  930. CK_ACTIVE:     TEST    STATUS,OFF              ;Is ANSI OFF?
  931.                JNZ     WRITE_TTY               ;If yes, write via BIOS TTY.
  932. CK_FAST:       CALL    CK_SLOW_TEXT            ;Is ANSI SLOW or in graphics
  933.                JNC     WRITE_FAST              ; mode? If no, write fast.
  934.  
  935.                CMP     AL,CR                   ;Let BIOS handle CR and LF.
  936.                JZ      WRITE_TTY
  937.                CMP     AL,LF
  938.                JZ      WRITE_TTY
  939.  
  940. WRITE_SLOW:    PUSH    AX                      ;Else, write character/attribute
  941.                MOV     CX,1                    ; at current cursor position
  942.                MOV     BH,ACTIVE_PAGE          ; via BIOS.
  943.                MOV     BL,ATTRIBUTE
  944.                MOV     AH,9
  945.                INT     10H
  946.                POP     AX
  947.  
  948.                CMP     LINE_WRAP,ON            ;Is line wrap on?
  949.                JZ      TTY                     ;If yes, continue.
  950.                MOV     CX,CRT_COLS             ;Else, cursor at rightmost
  951.                DEC     CL                      ; column?
  952.                CMP     CL,CURSOR_COL           ;If yes, continue, else
  953.                JNZ     TTY                     ; return without writing.
  954.                RET
  955.  
  956. ;------------------------------------------------;
  957.  
  958. WRITE_TTY:     MOV     BL,7                    ;Attribute in graphics mode.
  959. TTY:           MOV     AH,0EH
  960.                INT     10H
  961.                RET
  962.  
  963. ;----------------------------------------------------------------------------;
  964. ; Fast screen writes are directly to the video buffer without retrace check. ;
  965. ;----------------------------------------------------------------------------;
  966.  
  967. WRITE_FAST:    PUSH    ES                      ;Preserve extra segment.
  968.                MOV     DX,CURSOR_POSN          ;Retrieve cursor position.
  969.                CMP     AL,CR                   ;Carriage return?
  970.                JNZ     CK_LINEFEED             ;If no, check linefeed.
  971.                XOR     DL,DL                   ;Else, cursor to first column.
  972.                JMP     SHORT UPDATE_CURSOR
  973. CK_LINEFEED:   CALL    VIDEO_SETUP             ;Calculate video address.
  974.                CMP     AL,LF                   ;Linefeed?
  975.                JZ      NEXT_ROW                ;If yes, next row.
  976.  
  977.                MOV     AH,ATTRIBUTE            ;Retrieve attribute.
  978.                STOSW                           ;Put char/attrib in video buffer.
  979.                INC     DL                      ;Increment cursor column.
  980.                CMP     DL,BYTE PTR CRT_COLS    ;End of row?
  981.                JB      UPDATE_CURSOR           ;If no, update cursor.
  982.  
  983.                CMP     LINE_WRAP,OFF           ;Else, line wrap off?
  984.                JZ      FAST_END                ;If yes, don't move cursor.
  985.                XOR     DL,DL                   ;Else, column zero.
  986. NEXT_ROW:      INC     DH                      ;Next row.
  987.                CALL    INFORMATION             ;Get displayable row info.
  988.                CMP     DH,AL                   ;Beyond the bottom of screen?
  989.                JBE     UPDATE_CURSOR           ;If no, update cursor.
  990.  
  991.                DEC     DH                      ;Else, cursor to original row.
  992.                MOV     AX,CRT_COLS             ;. Get number of columns
  993.                PUSH    DX                      ;. Save Cursor position
  994.                PUSH    AX                      ;. Save Columns
  995.                SHL     AX,1                    ;. Twice for Char/Attribute
  996.                MOV     SI,AX                   ;. Starting offset in SI
  997.                MOV     DL,START_SCROLL         ;. Where we allow scroll to start
  998.                MUL     DL                      ;. Calculate offset in AX
  999.                SUB     DH,DL                   ;. Reduce line count
  1000.                MOV     DI,CRT_START            ;Point destination to top.
  1001.                ADD     DI,AX                   ;. Add offset
  1002.                ADD     SI,DI                   ;. Point source to second row
  1003.                POP     AX                      ;. Get Back Columns
  1004.                PUSH    AX                      ;. Save it again
  1005.                MUL     DH                      ;Times displayable rows - 1.
  1006.                MOV     CX,AX                   ; equals char/attrib to scroll.
  1007.                PUSH    DS                      ;Save data segment and
  1008.                PUSH    ES                      ; point to video segment.
  1009.                POP     DS
  1010.                REP     MOVSW                   ;Scroll the screen.
  1011.                POP     DS                      ;Restore data segment.
  1012.                POP     CX                      ;Retrieve CRT columns.
  1013.                POP     DX                      ;.Get back Cursor info
  1014.                MOV     AL,SPACE                ;Write space/attrib to
  1015.                MOV     AH,ATTRIBUTE            ; bottom row.
  1016.                REP     STOSW
  1017.  
  1018. UPDATE_CURSOR: CALL    SET_CURSOR              ;Update the cursor position.
  1019. FAST_END:      POP     ES                      ;Restore extra segment.
  1020.                RET
  1021. if PCB                                            ;$
  1022. ;@************ SUPPORT ROUTINES *************;
  1023.  
  1024. QOFF:          MOV     AL,0FFH                 ;& Show QOFF
  1025.                JMP     SHORT QON2              ;&
  1026. QON:           XOR     AL,AL                   ;& Show QON
  1027. QON2:          MOV     Q_STATE,AL              ;& Store the state
  1028.                RET                             ;& All done
  1029.  
  1030. BEEP:          MOV     AL,7                    ;@
  1031.                JMP     WRITE_CHAR              ;@
  1032. MORE:          MOV     AX,MORE_DELAY           ;@
  1033.                JMP     SHORT PAUSE2            ;@
  1034. PAUSE:         MOV     AX,PAUSE_DELAY          ;@
  1035. PAUSE2:        CMP     Q_STATE,0               ;& Are we at a QOFF state
  1036.                JNZ     WAIT1                   ;& Yes, then these are WAITs
  1037.                MOV     SI,OFFSET MORE_PROMPT   ;@ Point to More? Prompt
  1038.                MOV     CX,MORE_LENGTH          ;@ Get the Length of it
  1039.                JMP     SHORT WAIT2             ;@ Go Wait
  1040. WAIT1:         MOV     AX,WAIT_DELAY           ;@
  1041.                MOV     SI,OFFSET WAIT_PROMPT   ;@ Point to Wait Prompt
  1042.                MOV     CX,WAIT_LENGTH          ;@ Get the Length of it
  1043. WAIT2:         MOV     PAUSE_TIMER,AX          ;@
  1044. ;               PUSH    CX                      ;@ Save Length
  1045. WAIT2_LOOP:    LODSB                           ;@ Get Character
  1046.                PUSH    CX                      ;@
  1047.                PUSH    SI                      ;@
  1048.                CALL    WRITE_CHAR              ;@ Output it
  1049.                POP     SI                      ;@
  1050.                POP     CX                      ;@
  1051.                LOOP    WAIT2_LOOP              ;@ Do all the Characters
  1052. WAIT_LOOP:     MOV     AH,1                    ;@ KeyBoard Status
  1053.                INT     16H                     ;@ Keyboard I/O Services
  1054.                JNZ     CONTINUE                ;@ Key Hit!
  1055.                CMP     PAUSE_TIMER,0           ;@ Timer Run out?
  1056.                JNE     WAIT_LOOP               ;@ No
  1057.                JMP     SHORT WAIT3             ;@ Yes
  1058. CONTINUE:      MOV     AH,0                    ;@ KeyBoard Read
  1059.                INT     16H                     ;@ Keyboard I/O Services
  1060. WAIT3:                                         ;@
  1061.                XOR     CL,CL                   ;@ Clear the Attribute
  1062.                XCHG    CL,ATTRIBUTE            ;&  and
  1063.                PUSH    CX                      ;&    save it too
  1064.                MOV     DX,CURSOR_POSN          ;& Get Cursor
  1065.                MOV     DL,0                    ;& First column
  1066.                CALL    SET_CURSOR              ;& Set the new Cursor
  1067.                CALL    ERASE_2                 ;& Erase the line
  1068. ;&
  1069. ;& The following lines (and the PUSH CX above) will clear only the PROMPT
  1070. ;& and leave the cursor where it was when the prompt appears. This was
  1071. ;& different than PCBoard 14.5 so I changed it to clear the entire line
  1072. ;& via the above four lines. Left the old code in case someome wanted it.
  1073. ;&
  1074. ;&               POP     CX                      ;@ Get back Length
  1075. ;&ERASE_LOOP:    PUSH    CX                      ;@ Save it again
  1076. ;&               MOV     AL,BS                   ;@ Send BS
  1077. ;&               CALL    WRITE_CHAR              ;@  character
  1078. ;&               MOV     AL,' '                  ;@  and then space
  1079. ;&               CALL    WRITE_CHAR              ;@  character to erase
  1080. ;&               MOV     AL,BS                   ;@  then BS again
  1081. ;&               CALL    WRITE_CHAR              ;@  to backup.
  1082. ;&               POP     CX                      ;@ get back length again
  1083. ;&               LOOP    ERASE_LOOP              ;@ Erase entire prompt.
  1084.                POP     CX                      ;& Restore
  1085.                MOV     ATTRIBUTE,CL            ;&  the Attribute
  1086.                RET                             ;@
  1087. AUTOOFF:       MOV     AX,WAIT_DELAY           ;@ Restore More to a Wait
  1088.                JMP     SHORT AUTO2             ;@
  1089. AUTOMORE:      MOV     AX,PAUSE_DELAY          ;@ Make More a Pause
  1090. AUTO2:         MOV     MORE_DELAY,AX           ;@
  1091. SKIP_IT:       RET                             ;@
  1092. DELAY_IT:      PUSH    DX                      ;~ Save registers
  1093.                PUSH    BX                      ;~
  1094.                MOV     AX,182                  ;~ Multiply number by 182
  1095.                MOV     BX,100               ;` ;~ Then divide by 100
  1096.                XOR     DX,DX                   ;~ Prepare for division
  1097.                MUL     BYTE PTR NUMBER_BUFFER  ;~
  1098.                DIV     BX                      ;~
  1099.                MOV     PAUSE_TIMER,AX       ;` ;~ This should be Num * 1.82
  1100.                POP     BX                      ;~ Restore registers
  1101.                POP     DX                      ;~
  1102.                JMP     WAIT_LOOP               ;~ Now do the delay
  1103. POS_IT:        MOV     AL,BYTE PTR NUMBER_BUFFER ;~
  1104.                MOV     DX,CURSOR_POSN          ;~ Get Cursor
  1105.                INC     DL                      ;~ Adjust for ordinal
  1106.                SUB     AL,DL                   ;~ Are we beyond it already?
  1107.                JLE     POS_IT2                 ;~ Yes, nevermind
  1108.                MOV     CL,AL                   ;~ No, Put loop count in CX
  1109.                XOR     CH,CH                   ;~
  1110. POS_IT0:       MOV     AL,' '                  ;~ Write Spaces
  1111. POS_IT1:       PUSH    CX                      ;~ Save the count
  1112.                CALL    WRITE_CHAR              ;~
  1113.                POP     CX                      ;~ Restore the count
  1114.                LOOP    POS_IT1                 ;~ Until Done
  1115. POS_IT2:       RET                             ;~
  1116.  
  1117. endif                                             ;$
  1118. ; ************* SUPPORT ROUTINES ************* ;
  1119.  
  1120. CK_QUOTE:      MOV     BX,OFFSET QUOTE_STATE   ;Assume quote state.
  1121.                MOV     AH,DOUBLE_QUOTE
  1122.                CMP     AL,AH                   ;Is it double quote?
  1123.                JZ      GOT_QUOTE               ;If yes, string delimiter.
  1124.                MOV     AH,SINGLE_QUOTE         ;Is it single quote?
  1125.                CMP     AL,AH                   ;Is yes, string delimiter.
  1126.                JNZ     QUOTE_END               ;Else, return ZR = 0.
  1127. GOT_QUOTE:     MOV     QUOTE_TYPE,AH           ;Store as matching string end.
  1128. QUOTE_END:     RET
  1129.  
  1130. ;------------------------------------------------;
  1131.  
  1132. ACCUMULATE:    PUSH    AX                      ;Preserve number character.
  1133.                SUB     AL,'0'                  ;Convert ASCII to binary.
  1134.                MOV     CL,AL                   ;Save the number.
  1135.                MOV     AX,10                   ;Multiply previous count by 10.
  1136.                MOV     BX,NUMBER_COUNT
  1137.                MUL     BYTE PTR NUMBER_BUFFER[BX]
  1138.                ADD     AL,CL                            ;Add in new number
  1139.                MOV     BYTE PTR NUMBER_BUFFER[BX],AL    ; and store.
  1140.                POP     AX
  1141.                RET
  1142. if PCB                                            ;$
  1143. ;------------------------------------------------;@
  1144.  
  1145. ACCUM_COLOR:   PUSH    AX                      ;@ Preserve number character.
  1146.                SUB     AL,'0'                  ;@ Convert ASCII to hex
  1147.                MOV     AH,BYTE PTR NUMBER_BUFFER ;@ Get current number
  1148.                SHL     AH,1                      ;@ Shift left 4 bits
  1149.                SHL     AH,1                      ;@
  1150.                SHL     AH,1                      ;@
  1151.                SHL     AH,1                      ;@
  1152.                OR      AH,AL                     ;@ Add in new number
  1153.                MOV     BYTE PTR NUMBER_BUFFER,AH ;@ and store.
  1154.                MOV     CL,AH                     ;@ Return with Color in CL
  1155.                POP     AX                        ;@
  1156.                RET                               ;@
  1157.  
  1158. NUMBER_PARSE:  MOV  BX,[SI]                 ;@ Get low word
  1159.                MOV  DX,AX                   ;@ Variable Number in DX
  1160.                XOR  AX,AX                   ;@ Assume Integer
  1161.                CMP  CX,4                    ;@ Is that a Long Integer?
  1162.                JNE  SHORT_INT               ;@ No, Integer
  1163.                MOV  AX,[SI + 2]             ;@ Yes, Get high word
  1164. SHORT_INT:     MOV  DI, OFFSET PARSE_BUFFER ;@ Point DI at number space
  1165.                PUSH DI                      ;* save pointer
  1166.                MOV  CX,10                   ;@ Set divisor to 10
  1167.                XOR  SI,SI                   ;@ Clear SI as counter
  1168.                MOV  DH,255                  ;* Assume No Commas
  1169.                CMP  DL,COMMA_CODES          ;* Do we have commas?
  1170.                JB   SKIP_COMMAS             ;* No,
  1171.                MOV  DH,4                    ;* Yes, every fourth position
  1172. SKIP_COMMAS:   MOV  COMMA,2              ;@ ;* Assume a Ratio
  1173.                CMP  DL,2                    ;@ Is it a Ratio?
  1174.                JB   GETDIGIT                ;@ Yes,
  1175. RESET_COMMA:   MOV  COMMA,DH                ;@ No, Set Comma Counter
  1176. GETDIGIT:      DEC  DI                      ;@ Point DI at correct character
  1177.                INC  SI                      ;@ Register that we have a character
  1178.                DEC  COMMA                   ;@ Do we need a Comma?
  1179.                JNZ  NO_COMMA                ;@ No
  1180.                MOV  BYTE PTR [DI],','       ;@ Yes, So Put one in!
  1181.                JMP  RESET_COMMA             ;@ And restart the Comma count.
  1182. NO_COMMA:      PUSH DX                      ;* Save DX
  1183.                XOR  DX,DX                   ;@ Clear DX to take remainder
  1184.                DIV  CX                      ;@ Divide AX first (High word)
  1185.                MOV  BP,AX                   ;@ Save quotient
  1186.                MOV  AX,BX                   ;@ Get low word
  1187.                DIV  CX                      ;@ DX had leftover from first divide
  1188.                MOV  BX,AX                   ;@ Save quotient
  1189.                MOV  AX,BP                   ;@ Put high word back
  1190.                ADD  DL,30h                  ;@ Make it an ASCII digit from remainder
  1191.                MOV  [DI],DL                 ;@ Put it in our string
  1192.                POP  DX                      ;* Restore DX
  1193.                OR   AX,AX                   ;@ Is high word zero?
  1194.                JNZ  GETDIGIT                ;@ No keep going
  1195.                OR   BX,BX                   ;@ Is low word zero?
  1196.                JNZ  GETDIGIT                ;@ No keep going
  1197.                MOV  CX,SI                   ;@ Digit count to CX
  1198.                MOV  SI,DI                   ;@ String Pointer to SI
  1199.                POP  DI                      ;* Get back pointer
  1200.                CMP  BYTE PTR [DI][-2],',' ;*;@ Replace Comma with Decimal?
  1201.                JNE  NO_DECIMAL            ;*;@ No, Nevermind
  1202.                MOV  BYTE PTR [DI][-2],'.'   ;@ Change comma to Decimal
  1203. NO_DECIMAL:    CMP  DL,3                    ;* Was it a Ratio
  1204.                JA   NOT_RATIO               ;* No, Nevermind
  1205.                MOV  WORD PTR [DI],313Ah   ;*;@ Yes, Add ':1' to it
  1206.                ADD  CX,2                    ;@ Account for two more characers
  1207. NOT_RATIO:     RET                          ;@
  1208.  
  1209. MAKE_TIMEDATE: MOV  DI, OFFSET NUMBER_BUFFER ;@ Point to Number Buffer
  1210.                MOV  SI,DI            ;@ Save it in SI too
  1211.                JE   MAKE_TIME        ;@ It was TIME on Entry!
  1212.                MOV  CX,8             ;@ It was DATE! Length = 8
  1213.                PUSH CX               ;@ Save Length
  1214.                MOV  AH,04H           ;@ Get date service
  1215.                INT  1AH              ;@ Call BIOS - return codes as follows:
  1216.                PUSH CX               ;@ CH = Century (19-20)  CL = Year (00-99)
  1217.                PUSH DX               ;@ DH = Month   (1-12)   DL = Day  (00-31)
  1218.                MOV  AL,DH            ;@ Month
  1219.                CALL ASCII            ;@ Convert byte to ASCII digits
  1220.                MOV  AL,'-'           ;@
  1221.                STOSB                 ;@
  1222.                POP  AX               ;@ Day - was DX when pushed
  1223.                CALL ASCII            ;@ Convert byte to ASCII digits
  1224.                MOV  AL,'-'           ;@
  1225.                STOSB                 ;@
  1226.                POP  AX               ;@ Year - was CX when pushed
  1227.                POP  CX               ;@ Restore Length
  1228.                JMP  SHORT ASCII      ;@ Convert byte to ASCII digit
  1229.  
  1230. MAKE_TIME:     MOV  CX,5             ;@ Length = 5
  1231.                PUSH CX               ;@ Save Length
  1232.                MOV  AH,02H           ;@ Get time service
  1233.                INT  1AH              ;@ Call BIOS - return codes as follows:
  1234.                PUSH CX               ;@ CH = Hours   (0-23)   CL = Minutes (0-59)
  1235.                MOV  AL,CH            ;@ Hours
  1236.                CALL ASCII            ;@ Convert byte to ASCII digits
  1237.                MOV  AL,':'           ;@
  1238.                STOSB                 ;@
  1239.                POP  AX               ;@ Minutes - was CX when pushed
  1240.                POP  CX               ;@ Restore Length
  1241. ASCII:         MOV  AH,AL            ;@ Need to get BCD Digits
  1242.                SHR  AL,1             ;@  MSD in AL
  1243.                SHR  AL,1             ;@   lower
  1244.                SHR  AL,1             ;@     4
  1245.                SHR  AL,1             ;@     Bits
  1246.                AND  AH,0FH           ;@ And LSD in AH cleanly
  1247.                OR   AX,3030H         ;@ Convert to ASCII
  1248.                STOSW                 ;@ Stuff Digits into Buffer (in reverse)
  1249.                RET                   ;@ SI Points to String Data
  1250.  
  1251. endif                                   ;$
  1252. ;---------------------------------------------------------------------------;
  1253. ; OUTPUT:  CY = 1 if write SLOW mode or in graphics mode; CY = 0 otherwise. ;
  1254. ;---------------------------------------------------------------------------;
  1255.  
  1256. CK_SLOW_TEXT:  TEST    STATUS,SLOW
  1257.                JNZ     SLOW_MODE
  1258.                CMP     CRT_MODE,7
  1259.                JZ      TEXT_MODE
  1260.                CMP     CRT_MODE,3
  1261.                JA      SLOW_MODE
  1262. TEXT_MODE:     CLC
  1263.                RET
  1264.  
  1265. SLOW_MODE:     STC
  1266.                RET
  1267.  
  1268. ;-------------------------------------;
  1269. ; OUTPUT:  AL = Screen rows minus one ;
  1270. ;-------------------------------------;
  1271.  
  1272. INFORMATION:   PUSH    DS                      ;Save data segment.
  1273.                MOV     AX,40H                  ;Point to BIOS data.
  1274.                MOV     DS,AX
  1275.                MOV     AL,DS:[84H]             ;Retrieve rows - 1.
  1276.                OR      AL,AL                   ;BIOS supported?
  1277.                JNZ     INFO_END                ;If yes, done here.
  1278.                MOV     AL,24                   ;Else, assume 25 lines.
  1279. INFO_END:      POP     DS
  1280.                RET
  1281.  
  1282. ;------------------------------------------------------------------------------;
  1283. ; INPUT:  DX = Cursor position.                                                ;
  1284. ; OUTPUT: ES = Video buffer segment; DI = Video buffer offset; AX,DX preserved ;
  1285. ;------------------------------------------------------------------------------;
  1286.  
  1287. VIDEO_SETUP:   PUSH    AX
  1288.                MOV     AX,CRT_COLS             ;Retrieve CRT columns.
  1289.                MUL     DH                      ;Times cursor row.
  1290.                MOV     BL,DL
  1291.                XOR     BH,BH
  1292.                ADD     AX,BX                   ;Plus cursor column.
  1293.                SHL     AX,1                    ;Times two for attribute.
  1294.                MOV     DI,CRT_START            ;Plus starting video offset.
  1295.                ADD     DI,AX                   ;Equals destination.
  1296.  
  1297.                MOV     BX,0B000H               ;Assume mono card.
  1298.                CMP     ADDR_6845,3B4H          ;Is it mono port?
  1299.                JZ      VIDEO_SEGMENT           ;If yes, guessed right.
  1300.                ADD     BX,800H                 ;Else, point to color segment.
  1301. VIDEO_SEGMENT: MOV     ES,BX
  1302.                POP     AX
  1303.                RET
  1304.  
  1305. ;------------------------------------------------;
  1306. ; Move BIOS video data into our data segment.    ;
  1307. ;------------------------------------------------;
  1308.  
  1309. GET_BIOS_DATA: PUSH    DS
  1310.                PUSH    DI                      ;Point to BIOS data segment.
  1311.                MOV     BX,40H
  1312.                MOV     DS,BX
  1313.                MOV     SI,BIOS_ACTIVE_PAGE     ;Start with active page.
  1314.                MOV     DI,OFFSET ACTIVE_PAGE
  1315.                MOVSB                           ;Retrieve active page
  1316.                MOVSW                           ; and address of 6845 port.
  1317.                MOV     SI,BIOS_CRT_MODE        ;Retrieve CRT mode, CRT columns,
  1318.                MOV     CX,CRT_DATA_LENGTH      ; CRT length, CRT start.
  1319.                REP     MOVSB
  1320.                MOV     BL,ES:ACTIVE_PAGE       ;Use active page as index
  1321.                XOR     BH,BH                   ; of active cursor position.
  1322.                SHL     BX,1
  1323.                ADD     SI,BX
  1324.                MOVSW
  1325.                POP     DI
  1326.                POP     DS
  1327.                RET
  1328.  
  1329. ;----------------------------------------------------------------------------;
  1330. ; OUTPUT: BL = First parameter; BH = Second parameter; DX = cursor position. ;
  1331. ;----------------------------------------------------------------------------;
  1332.  
  1333. ADJUST_NUMBER: MOV     BX,WORD PTR NUMBER_BUFFER
  1334.                OR      BH,BH
  1335.                JNZ     ADJUST_AL               ;If either parameter zero,
  1336.                INC     BH                      ; increment to convert
  1337. ADJUST_AL:     OR      BL,BL                   ; to base one.
  1338.                JNZ     ADJUST_END
  1339.                INC     BL
  1340. ADJUST_END:    MOV     DX,CURSOR_POSN          ;Return cursor position.
  1341.                RET
  1342.  
  1343. ;--------------------------------------------------------------------------;
  1344. ; INPUT:  AX = number; BP = 0 if console output; BP = 1 if storage output. ;
  1345. ;--------------------------------------------------------------------------;
  1346.  
  1347. DECIMAL_OUT:   MOV     BX,10                   ;Divisor of ten.
  1348.                XOR     CX,CX                   ;Zero in counter.
  1349. NEXT_COUNT:    XOR     DX,DX                   ;Zero in high half.
  1350.                DIV     BX                      ;Divide by ten.
  1351.                ADD     DL,'0'                  ;Convert to ASCII.
  1352.                PUSH    DX                      ;Save results.
  1353.                INC     CX                      ;Also increment count.
  1354.                CMP     AX,0                    ;Are we done?
  1355.                JNZ     NEXT_COUNT              ;Continue until zero.
  1356.                OR      BP,BP                   ;If BP zero, output to screen.
  1357.                JNZ     DEVICE_OUTPUT           ;Else, store in buffer.
  1358.  
  1359. REPORT_OUTPUT: POP     AX                      ;Retrieve number.
  1360.                CALL    PRINT_CHAR              ;Display it.
  1361.                LOOP    REPORT_OUTPUT
  1362.                RET
  1363.  
  1364. DEVICE_OUTPUT: CMP     CX,2                    ;Two digits?
  1365.                JZ      TWO_DIGITS              ;If yes, process normally.
  1366.                MOV     AL,'0'                  ;Else, store leading zero.
  1367.                STOSB
  1368.  
  1369. TWO_DIGITS:    POP     AX                      ;Retrieve number.
  1370.                STOSB                           ;Store it
  1371.                LOOP    TWO_DIGITS
  1372.                RET
  1373.  
  1374. ; ************* ANSI COMMAND SUBSET ************* ;
  1375.  
  1376. CLS:           MOV     BH,7                    ;Assume normal attribute.
  1377.                MOV     BL,BYTE PTR CRT_MODE    ;Get current video mode.
  1378.                CMP     BL,4
  1379.                JBE     CK_CLS_STATUS           ;If text mode then check if
  1380.                CMP     BL,7                    ; ANSI active.
  1381.                JZ      CK_CLS_STATUS
  1382.                XOR     BH,BH                   ;Else, use black attribute
  1383.                TEST    STATUS,OFF
  1384.                JNZ     CLS_SLOW                ;If ANSI inactive, via BIOS.
  1385.                JMP     SHORT CK_CLS_SLOW       ;Else, check if FAST or SLOW.
  1386.  
  1387. CK_CLS_STATUS: TEST    STATUS,OFF              ;Is ANSI OFF?
  1388.                JNZ     CLS_SLOW                ;If yes, CLS via BIOS.
  1389.                MOV     BH,ATTRIBUTE            ;Else, current attribute.
  1390. CK_CLS_SLOW:   CALL    CK_SLOW_TEXT
  1391.                JC      CLS_SLOW                ;If ANSI SLOW, via BIOS.
  1392.  
  1393. CLS_FAST:      MOV     AH,BH                   ;Else, attribute in high half.
  1394.                MOV     AL,SPACE                ;Space character in low half.
  1395.                XOR     DX,DX                   ;Cursor position home.
  1396.                MOV     DH,START_SCROLL         ;$ protect lines
  1397.                CALL    VIDEO_SETUP             ;Calculate video address.
  1398.                MOV     CX,CRT_LEN              ;Retrieve CRT length.
  1399.                SHR     CX,1                    ;Times two for attribute.
  1400.                REP     STOSW                   ;Write directly to video buffer.
  1401.                JMP     SHORT SET_CURSOR        ;Set the cursor top left corner.
  1402.  
  1403. CLS_SLOW:      CALL    INFORMATION             ;Get displayable rows.
  1404.                MOV     DH,AL                   ;Store in DH.
  1405.                MOV     DL,BYTE PTR CRT_COLS    ;Retrieve CRT columns.
  1406.                DEC     DL                      ;Adjust to zero base.
  1407.                XOR     CX,CX                   ;Scroll active page.
  1408.                MOV     AX,600H
  1409.                INT     10H
  1410.                XOR     DX,DX                   ;Home the cursor.
  1411.                JMP     SHORT SET_CURSOR
  1412.  
  1413. ;------------------------------------------------;
  1414. CURS_POSITION:                                 ;These two commands are the same.
  1415. HORZ_VERT_POS: CALL    INFORMATION             ;Returns AL = screen rows.
  1416.                CALL    ADJUST_NUMBER           ;Returns BL,BH = parameters.
  1417.                SUB     BX,101H                 ;Zero based.
  1418.                CMP     BL,AL                   ;If cursor request within
  1419. ;$             JA      CURSOR_END              ; boundaries of screen, set it.
  1420.                JBE     ROWOK                   ;$boundaries of screen, set it.
  1421.                MOV     BL,AL                   ;$Set to last row
  1422. ROWOK:         CMP     BH,BYTE PTR CRT_COLS    ;$
  1423. ;$             JAE     CURSOR_END
  1424.                JB      COLOK                   ;$
  1425.                MOV     BH,BYTE PTR CRT_COLS    ;$Set to
  1426.                DEC     BH                      ;$       last column
  1427. COLOK:         XCHG    BH,BL                   ;
  1428.                MOV     DX,BX
  1429.  
  1430. SET_CURSOR:    MOV     BH,ACTIVE_PAGE          ;Set cursor via BIOS.
  1431.                MOV     AH,2
  1432.                INT     10H
  1433. CURSOR_END:    RET
  1434.  
  1435. ;------------------------------------------------;
  1436.  
  1437. CURSOR_UP:     CALL    ADJUST_NUMBER           ;Move cursor up one or more rows
  1438.                OR      DH,DH                   ; without changing column.
  1439.                JZ      CURSOR_END              ;If already at top, ignore.
  1440.                SUB     DH,BL
  1441.                JNC     SET_CURSOR              ;Stay in bounds.
  1442.                XOR     DH,DH
  1443.                JMP     SHORT SET_CURSOR
  1444.  
  1445. ;------------------------------------------------;
  1446.  
  1447. CURSOR_DOWN:   CALL    INFORMATION             ;Returns AL = screen rows.
  1448.                CALL    ADJUST_NUMBER           ;Returns BL,BH =nos.; DX = cursor
  1449.                CMP     DH,AL                   ;Move cursor down requested
  1450.                JZ      CURSOR_END              ; rows without changing column.
  1451.                ADD     DH,BL
  1452.                CMP     DH,AL
  1453.                JNA     SET_CURSOR
  1454.                MOV     DH,AL                   ;Stay in bounds.
  1455.                JMP     SHORT SET_CURSOR
  1456.  
  1457. ;------------------------------------------------;
  1458.  
  1459. CURS_FORWARD:  CALL    ADJUST_NUMBER           ;Returns BL,BH =nos.; DX = cursor
  1460.                MOV     BH,BYTE PTR CRT_COLS    ;Retrieve displayable columns.
  1461.                DEC     BH                      ;Adjust to zero base.
  1462.                CMP     DL,BH                   ;Move cursor forward one or more
  1463.                JZ      CURSOR_END              ; columns without changing row.
  1464.                ADD     DL,BL
  1465.                CMP     DL,BH
  1466.                JNA     SET_CURSOR
  1467.                MOV     DL,BH                   ;Stay in bounds.
  1468.                JMP     SHORT SET_CURSOR
  1469.  
  1470. ;------------------------------------------------;
  1471.  
  1472. CURS_BACKWARD: CALL    ADJUST_NUMBER           ;Returns BL,BH =nos.; DX = cursor
  1473.                OR      DL,DL                   ;Move cursor backward one or
  1474.                JZ      CURSOR_END              ; more columns without changing
  1475.                SUB     DL,BL                   ; row.  Ignore if already left.
  1476.                JNC     SET_CURSOR
  1477.                XOR     DL,DL                   ;Stay in bounds.
  1478.                JMP     SHORT SET_CURSOR
  1479.  
  1480. ;--------------------------------------------------------;
  1481. ; Report cursor position via console; Format: ESC[#;#R   ;
  1482. ;--------------------------------------------------------;
  1483.  
  1484. DEVICE_STATUS: MOV     DI,OFFSET DEVICE_STATUS_BUFFER
  1485.                MOV     AL,ESC_CHAR
  1486.                STOSB                           ;Store leading Esc, bracket
  1487.                MOV     AL,'['                  ;in special Device Status Buffer.
  1488.                STOSB
  1489.  
  1490.                MOV     AL,CURSOR_ROW           ;Retrieve cursor row.
  1491.                XOR     AH,AH                   ;Zero in high half.
  1492.                INC     AX                      ;Convert to base one.
  1493.                MOV     BP,1                    ;Flag as storage.
  1494.                CALL    DECIMAL_OUT             ;Convert to ASCII.
  1495.                MOV     AL,';'                  ;Store delimiting semi-colon.
  1496.                STOSB
  1497.                MOV     AL,CURSOR_COL           ;Do same with cursor column.
  1498.                XOR     AH,AH
  1499.                INC     AX
  1500.                CALL    DECIMAL_OUT
  1501.                MOV     AL,'R'                  ;Add command character
  1502.                STOSB
  1503.                MOV     AL,CR                   ; and carriage return.
  1504.                STOSB
  1505.                SUB     DI,OFFSET DEVICE_STATUS_BUFFER   ;Setup for console out.
  1506.                MOV     REASSIGN_COUNT,DI
  1507.                MOV     REASSIGN_POS,OFFSET DEVICE_STATUS_BUFFER
  1508.                MOV     REASSIGN_FLAG,ON
  1509.                MOV     REMOVE_FLAG,OFF
  1510.                RET
  1511.  
  1512. ;------------------------------------------------;
  1513.  
  1514. SAVE_CURSOR:   MOV     DX,CURSOR_POSN
  1515.                MOV     SAVE_POSITION,DX
  1516.                RET
  1517.  
  1518. ;------------------------------------------------;
  1519.  
  1520. RESTORE_CURS:  MOV     DX,SAVE_POSITION
  1521.                JMP     SET_CURSOR
  1522.  
  1523. ;------------------------------------------------;
  1524.  
  1525. ERASE_IN_LINE: MOV     DX,CURSOR_POSN          ;Erase from the cursor to
  1526. ERASE_2:       MOV     CX,CRT_COLS             ;& the end of the line, including
  1527.                SUB     CL,DL                   ; the current cursor position.
  1528.                CALL    CK_SLOW_TEXT
  1529.                JC      ERASE_SLOW              ;If ANSI ON and not graphics,
  1530.                CALL    VIDEO_SETUP             ; write directly to video buffer
  1531.                MOV     AL,SPACE                ; with space/attribute.
  1532.                MOV     AH,ATTRIBUTE
  1533.                REP     STOSW
  1534.                RET
  1535.  
  1536. ERASE_SLOW:    MOV     CX,DX                   ;Else, erase SLOW via
  1537.                MOV     DL,BYTE PTR CRT_COLS    ; BIOS scroll active page.
  1538.                DEC     DL
  1539.                MOV     BH,ATTRIBUTE
  1540.                MOV     AX,601H
  1541.                INT     10H
  1542.                RET
  1543.  
  1544. ;------------------------------------------------;
  1545. ;            Set Graphics Rendition              ;
  1546. ;------------------------------------------------;
  1547.  
  1548. SGR:           MOV     SI,OFFSET NUMBER_BUFFER     ;Point to number parameters.
  1549. NEXT_SGR:      LODSB                               ;Retrieve parameter.
  1550.                MOV     DI,OFFSET ATTRIBUTE_TABLE   ;Look up attribute in
  1551.                MOV     CX,ATTRIBUTE_LENGTH         ; translation table.
  1552.                REPNZ   SCASB
  1553.                JNZ     SGR_LOOP
  1554.  
  1555.                MOV     DI,OFFSET ATTRIBUTE_END
  1556.                SHL     CX,1
  1557.                SUB     DI,CX
  1558.                MOV     AX,[DI]
  1559.                AND     ATTRIBUTE,AL            ;If match, AND with strip mask.
  1560.                OR      ATTRIBUTE,AH            ;OR with add mask.
  1561. SGR_LOOP:      DEC     NUMBER_COUNT            ;Do all parameters.
  1562.                JNZ     NEXT_SGR
  1563.                RET
  1564.  
  1565. ;------------------------------------------------;
  1566.  
  1567. SET_MODE:      MOV     AH,ON                   ;Assume command 7,
  1568.                JMP     SHORT CK_WRAP           ; turn line wrap on.
  1569.  
  1570. ;------------------------------------------------;
  1571.  
  1572. RESET_MODE:    MOV     AH,OFF                     ;Assume turn line wrap off.
  1573. CK_WRAP:       MOV     AL,BYTE PTR NUMBER_BUFFER  ;Retrieve number parameter.
  1574.                CMP     AL,7                       ;Is it 7?
  1575.                JZ      SET_WRAP                ;If yes, set wrap mode.
  1576.                JB      DO_MODE                 ;1 - 6 valid modes.
  1577.                CMP     AL,14                   ;14 - 16 valid modes.
  1578.                JB      MODE_END
  1579.                CMP     AL,19
  1580.                JA      MODE_END                ;If above 16, illegal.
  1581. DO_MODE:       XOR     AH,AH                   ;Else, set video mode
  1582.                INT     10H                     ; to parameter.
  1583.                RET
  1584.  
  1585. SET_WRAP:      MOV     LINE_WRAP,AH
  1586. MODE_END:      RET
  1587.  
  1588. ;--------------------------------------------------------------------;
  1589. ; Keyboard Key Reassignment:  First convert ASCII numbers to binary, ;
  1590. ; parse out delimiting semi-colons, and quote string delimiters.     ;
  1591. ;--------------------------------------------------------------------;
  1592.  
  1593. REASSIGNMENT:  TEST    STATUS,POFF             ;:If assignment are OFF,
  1594.                JZ      NOT_POFF                ;:   then exit as if
  1595.                JMP     ASSIGN_FLUSH            ;:   we are out of room.
  1596. NOT_POFF:                                      ;:
  1597.                MOV     CX,ESC_COUNT            ;Retrieve length of Esc sequence.
  1598.                DEC     CX                          ;Adjust.
  1599.                MOV     SI,OFFSET ESC_BUFFER + 2    ;Point past Esc, bracket.
  1600.                MOV     DI,OFFSET PARSE_BUFFER      ;Point to parse storage.
  1601. NEXT_STRING:   MOV     QUOTE_TYPE,0                ;Reset quote type.
  1602. NEXT_NUM:      XOR     DL,DL                   ;Use DL to carry number; init = 0
  1603.                XOR     BP,BP                   ;Use BP as number flag.
  1604. NEXT_PARAM:    LODSB                           ;Retrieve a byte.
  1605.                DEC     CX                      ;Decrement string length counter.
  1606.                JZ      PARSE_END               ;If zero, done.
  1607.                MOV     AH,QUOTE_TYPE           ;Else, retrieve quote type.
  1608.                OR      AH,AH                   ;If zero, not in string.
  1609.                JNZ     QUOTE_MODE              ;Else, go to string mode.
  1610.                CALL    CK_QUOTE                ;Is character a quote?
  1611.                JZ      NEXT_PARAM              ;If yes, ignore.
  1612.                CMP     AL,';'                  ;Else, is it semi-colon?
  1613.                JZ      STORE_NUMBER            ;If yes, number delimiter.
  1614.  
  1615.                SUB     AL,'0'                  ;Else, must be number; convert
  1616.                MOV     DH,AL                   ; to binary; save in DH.
  1617.                MOV     AX,10                   ;Multiply current total by ten.
  1618.                MUL     DL
  1619.                ADD     AL,DH                   ;Add new number.
  1620.                MOV     DL,AL                   ;Save in DL.
  1621.                MOV     BP,1                    ;Flag that number mode active.
  1622.                JMP     SHORT NEXT_PARAM        ;Next parameter.
  1623.  
  1624. STORE_NUMBER:  OR      BP,BP                   ;If number mode flag not set then
  1625.                JZ      NEXT_PARAM              ;semi-colon not prefaced with no.
  1626.                MOV     AL,DL                   ;Else, store number.
  1627.                STOSB
  1628.                JMP     SHORT NEXT_NUM          ;Reset number carrying registers.
  1629.  
  1630. QUOTE_MODE:    CMP     AL,AH                   ;Is current char a string ending
  1631.                JZ      NEXT_STRING             ; quote?  If yes, exit quote mode
  1632.                STOSB                           ;Else, store char as literal.
  1633.                JMP     SHORT NEXT_PARAM
  1634.  
  1635. ;----------------------------------------------------------------------------;
  1636. ; Remove duplicate assignments if removal leaves room for new assignment.    ;
  1637. ; If no duplicate and room, add new assignment, else flush buffer to screen. ;
  1638. ;----------------------------------------------------------------------------;
  1639.  
  1640. PARSE_END:     OR      BP,BP                   ;Was last parameter a number?
  1641.                JZ      CK_LENGTH               ;If no, skip.
  1642.                MOV     AL,DL                   ;Else, store the last number.
  1643.                STOSB
  1644. CK_LENGTH:     SUB     DI,OFFSET PARSE_BUFFER - 2   ;Calculate string length
  1645.                MOV     AX,DI                        ; including word for length.
  1646.                MOV     BX,WORD PTR PARSE_BUFFER     ;BL=new first ASCII; BH=2nd.
  1647.                MOV     CX,4                         ;String length has to be at
  1648.                OR      BL,BL                  ;+least word + 2 for old = 4
  1649.                JZ      CK_LEGAL                ; for extended key reassignment.
  1650.                DEC     CX                      ;And word + 1 for old = 3
  1651. CK_LEGAL:      CMP     AX,CX                   ; for regular ASCII reassignment.
  1652.                JB      ASSIGN_FLUSH            ;If not, illegal; flush buffer.
  1653.                JNE     DOCHK                   ;+If equal then unassign.
  1654.                XOR     AX,AX                   ;+
  1655. DOCHK:         MOV     BP,BUFFER_END           ;BP to carry buffer end pointer.
  1656.                CALL    CK_MATCH                ;Is char already reassigned?
  1657.                JC      CK_ROOM                 ;If no, check room for new.
  1658.  
  1659. CK_REMOVE:     MOV     CX,DX                   ;REASSIGN_END - string end
  1660.                SUB     CX,SI                   ; = bytes to move.
  1661.                JZ      CK_ROOM                 ;If zero, last string.
  1662.                SUB     DX,[DI]                 ;Is REASSIGN_END - old string
  1663.                ADD     DX,AX                   ; + new string >
  1664.                CMP     DX,BP                   ; BUFFER_END?
  1665.                JA      ASSIGN_FLUSH            ;If yes, flush buffer to screen.
  1666.                REP     MOVSB                   ;Else, move them down in buffer.
  1667.                JMP     SHORT STORE_NEW
  1668.  
  1669. CK_ROOM:       ADD     DX,AX                   ;New string + current strings.
  1670.                CMP     DX,BP                   ;Greater than buffer size?
  1671.                JA      ASSIGN_FLUSH            ;If yes, flush new string.
  1672. STORE_NEW:     MOV     SI,OFFSET PARSE_BUFFER  ;Else, room for new string.
  1673.                TEST    AX,255                  ;+Any reassign?
  1674.                JZ      NOREASG                 ;+no reassignment
  1675.                STOSW                           ;Store string length first.
  1676.                MOV     CX,AX                   ;Adjust counter.
  1677.                DEC     CX
  1678.                DEC     CX
  1679.                REP     MOVSB                   ;Store the actual string.
  1680. NOREASG:       MOV     REASSIGN_END,DI         ;+Store new string end.
  1681.                RET
  1682.  
  1683. ASSIGN_FLUSH:  CMP     AX,2                    ;+Any key number?
  1684.                JNE     FLUSHIN                 ;+no
  1685.                MOV     AX,OFFSET REASSIGNMENT_BUFFER
  1686.                MOV     REASSIGN_END,AX         ;+flush all reassigns.
  1687.                RET                             ;+
  1688. FLUSHIN:       MOV     AL,'p'                  ;+If buffer full, flush string
  1689.                JMP     FLUSH_BUFFER            ; including ending 'p' command.
  1690.  
  1691. ;------------------------------------------------------------------------------;
  1692. ; INPUT:  BL = first ASCII code to match; BH = extended if BL = 0              ;
  1693. ; OUTPUT: CY = 1 if no match found; CY = 0 if match found.                     ;
  1694. ;         DI points to string length of match; DI+2 points to start of string. ;
  1695. ;         SI = end of string; DX = REASSIGN_END; BP = BUFFER_END               ;
  1696. ;------------------------------------------------------------------------------;
  1697.  
  1698. CK_MATCH:      MOV     DX,REASSIGN_END                ;Current strings end.
  1699.                MOV     SI,OFFSET REASSIGNMENT_BUFFER  ;Point to buffer.
  1700. NEXT_MATCH:    MOV     DI,SI                          ;Current record.
  1701.                CMP     DI,DX                   ;End of strings?
  1702.                JAE     NO_MATCH                ;If yes, no match.
  1703.                MOV     CX,[DI+2]               ;CL=current first ASCII; CH=2nd
  1704.                ADD     SI,[DI]                 ;Point to next record.
  1705.                CMP     BL,CL                   ;First characters match?
  1706.                JNZ     NEXT_MATCH              ;If no, check next record.
  1707.                OR      BL,BL                   ;Extended code? ie zero.
  1708.                JNZ     MATCH                   ;If no, then match.
  1709.                CMP     BH,CH                   ;Else, check second code.
  1710.                JNZ     NEXT_MATCH              ;If not same, no match.
  1711. MATCH:         CLC                             ;Else return with CY = 0
  1712.                RET
  1713.  
  1714. NO_MATCH:      STC                             ;No match; CY = 1.
  1715.                RET
  1716.  
  1717. ;----------------------------------------------------------------------;
  1718. ; Buffer area will write over disposable data and initialization code. ;
  1719. ;----------------------------------------------------------------------;
  1720.  
  1721. ESC_BUFFER            =       $
  1722. NUMBER_BUFFER         =       ESC_BUFFER + ESC_BUFFER_SIZE
  1723. PARSE_BUFFER          =       NUMBER_BUFFER - 2                         ;*
  1724. DEVICE_STATUS_BUFFER  =       NUMBER_BUFFER + ESC_BUFFER_SIZE           ;*
  1725. DEVICE_STATUS_SIZE    =       11
  1726. REASSIGNMENT_BUFFER   =       DEVICE_STATUS_BUFFER + DEVICE_STATUS_SIZE
  1727.  
  1728. ;              DISPOSABLE DATA
  1729. ;              ---------------
  1730.  
  1731. SYNTAX         LABEL   BYTE
  1732. DB      'Syntax:  ANSI [FAST | SLOW][ON | OFF][KON | KOFF][PON | POFF]'     ;^
  1733. if PCB                                           ;^
  1734. DB      '[XON | XOFF]'                           ;^
  1735. endif                                            ;^
  1736. DB      CR,LF ;:                                 ;^
  1737. DB      '              [/B nnn][/C][/Q][/U][/T][/S][/P n]',CR,LF ;. ;@      ;:
  1738. DB      'FAST     = direct screen writes; default',CR,LF                    ;:
  1739. DB      'SLOW     = screen writes via BIOS',CR,LF                           ;:
  1740. DB      'ON/OFF   = active/inactive; default is ON',CR,LF                   ;:
  1741. DB      'KON/KOFF = active/inactive reassignments; default is ON',CR,LF     ;:
  1742. DB      'PON/POFF = active/inactive NEW reassignments; default is ON',CR,LF ;:
  1743. if PCB                                           ;^
  1744. DB      'XON/XOFF = active/inactive @Xnn color codes; default is ON',CR,LF  ;^
  1745. endif                                            ;^
  1746. DB      'nnn = buffer size in bytes (0 - 60K) reserved for key reassignment; '
  1747. DB      'default 200',CR,LF
  1748. DB      '/Q  = Quiet, no output when executed',CR,LF                        ;:
  1749. DB      '/U  = Uninstall',CR,LF                                             ;:
  1750. DB      '/T  = Test if loaded',CR,LF                                        ;$
  1751. if PCB                                            ;$
  1752. DB      '/S  = Load stats from ANSICOM.SYS',CR,LF                           ;@
  1753. endif                                             ;$
  1754. DB      '/Pn = Protect n lines from scrolling at top'                       ;.
  1755. CR_LF   DB     CR,LF,LF,'$'
  1756.  
  1757. STATUS_MSG     DB      'Status: $'
  1758. BUFFER_MSG     DB      CR,LF,'Buffer size: $'
  1759. BYTES_FREE     DB      CR,LF,'Bytes free:  $'
  1760. ANSI_SYS_MSG   DB      'ANSI.SYS is installed so '
  1761. NOT_INSTALLED  DB      'ANSI.COM not installed',CR,LF,'$'
  1762. CON            DB      'CON'
  1763. CON_OFFSET     EQU     10
  1764. QUIET          DB      0                             ;| Quiet Mode
  1765. SYNTAX_FLAG    DB      0                             ;; Syntax Display Flag
  1766. TEST_FLAG      DW      0                             ;^ For report use
  1767.  
  1768. SIZE_MSG       DB      'Uninstall to change buffer size',CR,LF,LF,'$'
  1769. UNLOAD_MSG     DB      'ANSI can not be uninstalled',CR,LF
  1770.                DB      'Uninstall resident programs in reverse order',CR,LF,'$'
  1771. NOT_ENOUGH     DB      'Not enough memory',CR,LF,'$'
  1772. ALLOCATE_MSG   DB      'Memory allocation error',CR,LF,BELL,'$'
  1773. INSTALL_MSG    DB      'Installed',CR,LF,'$'
  1774. UNINSTALL_MSG  DB      'Uninstalled',CR,LF,'$'
  1775. if PCB                                            ;$
  1776. NO_FILE_MSG    DB      'ANSICOM.SYS not found',CR,LF,'$'                ;@
  1777. FILE_ERROR_MSG DB      'Error reading ANSICOM.SYS',CR,LF,'$'            ;@
  1778. FILE_NAME      DB      'ANSICOM.SYS',0                                  ;@
  1779. endif                                             ;$
  1780. alrdy_installed db      0                       ;^ Installed flag
  1781. other_seg       dw      0                       ;^ Segment of installed code
  1782. errmsg0         db      'Need DOS 2.0 or greater!$' ;^
  1783. errmsg14        db      'Error using Int 2Fh!$'     ;^
  1784.  
  1785. INITIALIZE     PROC    NEAR
  1786. ;--------------------------------------------------------------------;
  1787. ; Search memory for a copy of our code, to see if already installed. ;
  1788. ;--------------------------------------------------------------------;
  1789.  
  1790.                cld                             ;^
  1791.                mov     ah,30h                  ;^ Get DOS version
  1792.                int     21h                     ;^
  1793.                xchg    al,ah                   ;^ Swap major, minor numbers
  1794.                mov     dx,offset errmsg0       ;^ Bad DOS version
  1795.                cmp     ah,2                    ;^ Run if DOS 2.0 or greater.
  1796.                jb      jmp_msg_exit            ;^
  1797.                mov     dos_version,ax          ;^ Save version number
  1798. ;^
  1799. ;^ See if a copy is already resident in memory. If > DOS 3.0, use int 2Fh.
  1800. ;^
  1801.                mov     byte ptr [start+2],0    ;^ Initialize fingerprint
  1802.                cmp     dos_version,300h        ;^ See if DOS 3.0 or later
  1803.                jb      find_copy1              ;^ No, search the old way.
  1804.                mov     cx,16                   ;^ Try 16 different IDs.
  1805. find_copy:                                     ;^
  1806.                xor     ax,ax                   ;^
  1807.                mov     es,ax                   ;^
  1808.                mov     ah,multiplex_id         ;^ Load ID.  Use Int 2Fh to
  1809.                int     2fh                     ;^   reach installed code so
  1810.                or      al,al                   ;^   that we are compatible
  1811.                jne     find_copy0              ;^   with 386 memory managers.
  1812.                push    cs                      ;^
  1813.                pop     es                      ;^ If AL not changed, ALIAS not
  1814.                jmp     short find_copy4        ;^   installed.
  1815. find_copy0:                                    ;^
  1816.                push    cx                      ;^
  1817.                call    cmpheader               ;^ See if really Alias by
  1818.                pop     cx                      ;^   comparing file headers.
  1819.                je      find_copy3              ;^
  1820.                inc     multiplex_id            ;^ ID used by another program.
  1821.                loop    find_copy               ;^   Change and try again.
  1822.                mov     dx,offset errmsg14      ;^ All IDs taken, print error
  1823. jmp_msg_exit:  jmp     msg_exit                ;^   msg and exit.
  1824. ;
  1825. ;^ For DOS 2.x find the installed code the old fashioned way by scanning
  1826. ;^ the memory control blocks.
  1827. ;^
  1828. find_copy1:                                    ;^
  1829.                xor     bx,bx                   ;^ zero BX for start
  1830.                mov     ax,cs                   ;^ keep CS value in AX
  1831. find_copy2:                                    ;^
  1832.                inc     bx                      ;^ increment search segment value
  1833.                mov     es,bx                   ;^
  1834.                assume  es:nothing              ;^
  1835.                cmp     ax,bx                   ;^ not installed if current
  1836.                je      find_copy4              ;^   segment is found.
  1837.                call    cmpheader               ;^
  1838.                jne     find_copy2              ;^ loop back if not found
  1839. find_copy3:                                    ;^
  1840.                inc     alrdy_installed         ;^ Set installed flag
  1841. find_copy4:                                    ;^
  1842.                mov     other_seg,es            ;^ Save seg of installed code
  1843. ;^                CLD                             ;All string operations forward.
  1844. ;^                MOV     BX,OFFSET START         ;Point to start of code.
  1845. ;^                NOT     BYTE PTR [BX]           ;Change a byte so no false match.
  1846. ;^                XOR     DX,DX                   ;Start at segment zero.
  1847. ;^                MOV     AX,CS                   ;Store our segment in AX.
  1848. ;^ NEXT_PARAG:    INC     DX                      ;Next paragraph.
  1849. ;^                MOV     ES,DX
  1850. ;^                CMP     DX,AX                   ;Is it our segment?
  1851. ;^                JZ      ANNOUNCE                ;If yes, search is done.
  1852. ;^                MOV     SI,BX                   ;Else, point to our signature.
  1853. ;^                MOV     DI,BX                   ; and offset of possible match.
  1854. ;^                MOV     CX,16                   ;Check 16 bytes for match.
  1855. ;^                REP     CMPSB
  1856. ;^                JNZ     NEXT_PARAG              ;If no match, keep looking.
  1857.  
  1858. ;------------------------------------------------;
  1859.  
  1860. ANNOUNCE:                                      ;|
  1861.                MOV     SI,81H                  ;Point to command line.
  1862. NEXT_CAP:      LODSB                           ;Capitalize parameters.
  1863.                CMP     AL,CR
  1864.                JZ      PARSE
  1865.                CMP     AL,'a'
  1866.                JB      NEXT_CAP
  1867.                CMP     AL,'z'
  1868.                JA      NEXT_CAP
  1869.                AND     BYTE PTR [SI - 1],5FH
  1870.                JMP     SHORT NEXT_CAP
  1871.  
  1872. ;------------------------------------------------;
  1873.  
  1874. PARSE:         MOV     SI,81H                  ;Point to command line again.
  1875. NEXT_PARA:     XOR     AX,AX                   ;Position in status parameters.
  1876.                MOV     BX,4                    ;Status parameters each 4 bytes.
  1877. NEXT_STATUS:   MOV     DI,OFFSET PARAMETERS    ;Point to 'OFF ON  SLOWFAST'
  1878.                ADD     DI,AX                   ;Point to next parameter.
  1879.                ADD     AX,BX
  1880.                CMP     AX,LAST_PARAMETER       ;:Check all 8 possible statuses
  1881.                JA      CK_SWITCHES
  1882.                PUSH    SI                      ;Save command line pointer.
  1883.                MOV     CX,2                    ;Check first two bytes for match.
  1884.                CMP     AX,20                   ;: 3 Bytes for
  1885.                JB      Len_OK                  ;:   KON | KOFF | PON | POFF
  1886.                INC     CX                   ;: ;^   XON | XOFF
  1887. Len_OK:                                        ;:
  1888.                REP     CMPSB
  1889.                POP     SI                      ;Recover command line pointer.
  1890.                JNZ     NEXT_STATUS
  1891.  
  1892.                DIV     BL                      ;If match, divide offset by four.
  1893. ;:
  1894. ;:  Next 12 lines of routine changed
  1895. ;:
  1896. ;:             MOV     CL,1                    ;Set a bit to match offset.
  1897. ;:NEXT_SHIFT:  SHL     CL,1
  1898. ;:             DEC     AL
  1899. ;:             JNZ     NEXT_SHIFT
  1900. ;:             SHR     CL,1                    ;Adjust.
  1901. ;:             MOV     AH,STATUS_MASK          ;Retrieve appropriate ON/OFF
  1902. ;:             CMP     CL,ON                   ; or FAST/SLOW mask.
  1903. ;:             JBE     ADD_STATUS
  1904. ;:             ROL     AH,1
  1905. ;:             ROL     AH,1
  1906. ;:
  1907. ;:ADD_STATUS:  AND     ES:STATUS,AH            ;Mask off old status.
  1908. ;:             OR      ES:STATUS,CL            ;Add new status.
  1909. ;:
  1910.                MOV     CL,AL                ;: ;^ place count in CL (1 - 10)
  1911.                PUSH    DX                      ;^ Save Segment
  1912.                MOV     AX,AND_MASK          ;: ;^ Retrieve appropriate ON/OFF
  1913.                                                ;: FAST|SLOW|KON|KOFF|PON|POFF
  1914.                MOV     DX,OR_MASK              ;^ XON|XOFF
  1915.                DEC     CL                   ;: ;^ Make 1 - 10 into 0 - 9
  1916.                JZ      Skip_1                  ;: In position already if zero
  1917.                SHL     DX,CL                ;: ;^ Shift bit into position
  1918. Skip_1:        SHR     CL,1                    ;: divide count by 2
  1919.                JZ      Skip_2                  ;: Nevermind
  1920.                ROL     AX,CL                ;: ;^ Shift Mask into position
  1921.                ROL     AX,CL                ;: ;^
  1922. Skip_2:                                        ;:
  1923.  
  1924.                AND     ES:STATUS,AX            ;^ Mask off old status.
  1925.                OR      ES:STATUS,DX         ;: ;^ Add new status.
  1926.                POP     DX                      ;^ get back segment
  1927.                INC     SI                      ;Bump command line pointer.
  1928.                INC     SI
  1929.  
  1930. CK_SWITCHES:   LODSB                           ;Get a byte.
  1931.                CMP     AL,CR                   ;Is it carriage return?
  1932.                JNE     QUES                    ;$
  1933.                JMP     INSTALL                 ;If yes, done here.
  1934. QUES:          CMP     AL,'?'                  ;;Request for Syntax?
  1935.                JNE     CK_SW                   ;; No -
  1936.                MOV     BYTE PTR SYNTAX_FLAG, 1 ;; Yes-Show Syntax
  1937. CK_SW:         CMP     AL,'/'                  ;;Is there a switch character?
  1938.                JNE     NEXT_PARA               ;;If no, keep looking.
  1939. GOT_SWITCH:    LODSB                           ;;Else, get the switch character.
  1940.                CMP     AL,'B'                  ;Is it 'B' ?
  1941.                JNZ     CK_C                    ;If no, check 'C'.
  1942.                CALL    CK_INSTALLED            ;Else, see if already installed.
  1943.                JZ      GET_SIZE                ;If no, get buffer request size.
  1944.                MOV     DX,OFFSET SIZE_MSG      ;Else, display error message.
  1945.                CALL    PRINT_STRING
  1946. NEXT_PARA2:    JMP     SHORT NEXT_PARA
  1947. GET_SIZE:      CALL    DECIMAL_INPUT           ;Get number parameter.
  1948.                CMP     BX,REASSIGNMENT_MAX     ;If greater than maximum, use
  1949.                JBE     STORE_BUFFER            ; maximum, else use requested
  1950.                MOV     BX,REASSIGNMENT_MAX     ; size.
  1951. STORE_BUFFER:  MOV     REASSIGNMENT_SIZE,BX
  1952.                ADD     BX,OFFSET REASSIGNMENT_BUFFER  ;Calculate end of buffer.
  1953.                MOV     BUFFER_END,BX
  1954.                JMP     NEXT_PARA               ;;Too far for direct jump
  1955.  
  1956. CK_C:          CMP     AL,'C'                  ;Is it 'C' ?
  1957. if PCB                                         ;$
  1958.                JNZ     CK_S                    ;@ If not, check 'S'.
  1959. else                                           ;$
  1960.                JNZ     CK_P                    ;$ If not, check 'P'.
  1961. endif                                          ;$
  1962.                MOV     ES:REASSIGN_END,OFFSET REASSIGNMENT_BUFFER  ;Clear buffer
  1963.                JMP     NEXT_PARA               ;Else, next parmater.
  1964. if PCB                                         ;$
  1965. CK_S:          CMP     AL,'S'                  ;@ Is It 'S' ?
  1966.                JNZ     CK_P                    ;. If not, check 'P'.
  1967.                CALL    LOAD_STATS              ;@ Yes, Load Stats
  1968.                JMP     NEXT_PARA2              ;@ Next parameter (indirect)
  1969. endif                                          ;$
  1970. CK_P:          CMP     AL,'P'                  ;. Is it 'P' ?
  1971.                JNZ     CK_Q                    ;|If not, check 'Q'.
  1972.                CMP     BYTE PTR [SI], '*'      ;$Use current row-1?
  1973.                JNE     CK_PN                   ;$no
  1974.                PUSH    SI                      ;$Get
  1975.                CALL    GET_BIOS_DATA           ;$   current
  1976.                MOV     BL, ES:CURSOR_ROW       ;$          row
  1977.                DEC     BL                      ;$             -1
  1978.                POP     SI                      ;$
  1979.                JMP     CK_PS                   ;$
  1980. CK_PN:         CALL    DECIMAL_INPUT           ;. Get number of lines
  1981. CK_PS:         MOV     ES:START_SCROLL,BL      ;. Store the value
  1982.                JMP     NEXT_PARA2              ;. Next parameter (indirect)
  1983. CK_Q:          CMP     AL,'Q'                  ;|See if Quiet Mode
  1984.                JNE     CK_U                    ;|If not, check 'U'.
  1985.                NOT     QUIET                   ;|If yes turn on Quiet
  1986.                JMP     NEXT_PARA               ;Else, next parmater.
  1987. CK_U:          CMP     AL,'U'                  ;Is it 'U' ?
  1988.                JE      DO_U                    ;If yes, try to uninstall.
  1989.                CMP     AL,'T'                  ;; Test if Installed
  1990.                JE      DO_U
  1991.                MOV     BYTE PTR SYNTAX_FLAG, 1 ;; Syntax Error
  1992.                JMP     NEXT_PARA               ;Else, next parmater.
  1993.  
  1994. ;------------------------------------------------;
  1995.  
  1996. INSTALL:
  1997.                MOV     DX,OFFSET SIGNATURE     ;|Display our signature.
  1998.                CALL    PRINT_STRING            ;|
  1999.                CMP     BYTE PTR SYNTAX_FLAG,0  ;;Display Syntax?
  2000.                JE      SKIP_SYNTAX             ;;No
  2001.                MOV     DX,OFFSET SYNTAX        ;|Yes, Display syntax.
  2002.                CALL    PRINT_STRING            ;|
  2003. SKIP_SYNTAX:   CALL    STATUS_REPORT          ;;|Display status.
  2004.                CALL    CK_INSTALLED            ;Check if already installed.
  2005.                JZ      CK_AVAILABLE            ;If no, see if enough memory.
  2006.                XOR     AL,AL                   ;;Else, done.
  2007. EXIT2:         JMP     EXIT                    ;Exit with ERRORLEVEL = 0.
  2008.  
  2009. DO_U:          CALL    CK_INSTALLED            ;Else, see if installed.
  2010.                MOV     DX,OFFSET NOT_INSTALLED ;If no, exit with error message.
  2011.                JZ      LILLY_PAD               ;Too far for short jump.
  2012.                CMP     AL,'T'                  ;;Was it a test
  2013.                MOV     AX, STATUS              ;$return switches as ;^
  2014.                JE      EXIT2                   ;;$Yes Too far for short jump.
  2015.                JMP     UNINSTALL               ;$Else, uninstall.
  2016.  
  2017. ;--------------------------------;
  2018. ; This is the install procedure. ;
  2019. ;--------------------------------;
  2020.  
  2021. CK_AVAILABLE:  MOV     BP,OFFSET REASSIGNMENT_BUFFER   ;TSR ends at end
  2022.                ADD     BP,REASSIGNMENT_SIZE            ; of reassignment buffer.
  2023.                ADD     BP,15                           ;Round up.
  2024.                CMP     BP,DS:[6]               ;Buffer > PSP bytes in segment?
  2025.                MOV     DX,OFFSET NOT_ENOUGH    ;If yes, exit without installing
  2026.                JBE     CK_ANSI                 ;@
  2027. LILLY_PAD:     JMP     MSG_EXIT                ;@with message
  2028. CK_ANSI:       MOV     AX,3529H                ;@Get undocumented INT 29 vector.
  2029.                INT     21H
  2030.                MOV     SI,OFFSET CON           ;Does it point to ANSI.SYS?
  2031.                MOV     DI,CON_OFFSET           ;Check by looking for 'CON'
  2032.                MOV     CX,3                    ; as device name.
  2033.                REP     CMPSB
  2034.                MOV     DX,OFFSET ANSI_SYS_MSG  ;Exit with error message if
  2035.                JZ      LILLY_PAD               ;ANSI.SYS loaded.
  2036.  
  2037.                MOV     OLD_INT_29[0],BX        ;Else save old interrupt.
  2038.                MOV     OLD_INT_29[2],ES
  2039.                MOV     DX,OFFSET ANSI_INT_29   ;Install new interrupt.
  2040.                MOV     AX,2529H
  2041.                INT     21H
  2042.                MOV     AX,3516H                ;Get INT 16 vector.
  2043.                INT     21H
  2044.                MOV     OLD_INT_16[0],BX        ;Save old interrupt.
  2045.                MOV     OLD_INT_16[2],ES
  2046.                MOV     DX,OFFSET ANSI_INT_16   ;Install new interrupt.
  2047.                MOV     AX,2516H
  2048.                INT     21H
  2049.                MOV     AX,3521H                ;Get DOS 21h interrupt.
  2050.                INT     21H
  2051.                MOV     OLD_INT_21[0],BX        ;Save old interrupt.
  2052.                MOV     OLD_INT_21[2],ES
  2053.                MOV     DX,OFFSET ANSI_INT_21   ;Install new interrupt.
  2054.                MOV     AX,2521H
  2055.                INT     21H
  2056. if PCB                                            ;$
  2057.                MOV     AX,3508H                ;@ Get INT 08 vector.
  2058.                INT     21H                     ;@
  2059.                MOV     OLD_INT_08[0],BX        ;@ Save old interrupt.
  2060.                MOV     OLD_INT_08[2],ES        ;@
  2061.                MOV     DX,OFFSET ANSI_INT_08   ;@ Install new interrupt.
  2062.                MOV     AX,2508H                ;@
  2063.                INT     21H                     ;@
  2064. endif                                             ;$
  2065.                cmp     dos_version,300h        ;^ See if we are using Int 2Fh
  2066.                jb      install_3               ;^
  2067.                mov     ax,352fh                ;^ Get interrupt 2F (MUX)
  2068.                int     21h                     ;^  vector.
  2069.                mov     word ptr [int2fh],bx    ;^
  2070.                mov     word ptr [int2fh+2],es  ;^
  2071.                mov     ax,252fh                ;^ Point int 2F to internal
  2072.                mov     dx,offset muxint        ;^  routine.
  2073.                int     21h
  2074. Install_3:                                     ;^
  2075.  
  2076.                MOV     AX,DS:[2CH]             ;Get environment segment.
  2077.                MOV     ES,AX
  2078.                MOV     AH,49H                  ;Free up environment.
  2079.                INT     21H
  2080.  
  2081.                MOV     DX,OFFSET INSTALL_MSG   ;Display install message.
  2082.                CALL    PRINT_STRING
  2083.                CALL    FLUSH_END               ;Setup the number buffer.
  2084.                MOV     DX,BP                   ;Retrieve resident byte request.
  2085.                MOV     CL,4
  2086.                SHR     DX,CL                   ;Convert to paragraphs.
  2087.                MOV     AX,3100H                ;Return error code of zero.
  2088.                INT     21H                     ;Terminate but stay resident.
  2089.  
  2090. ;-------------------------------------------------------------------;
  2091. ; Exit.  Return ERRORLEVEL code 0 if successful, 1 if unsuccessful. ;
  2092. ;-------------------------------------------------------------------;
  2093.  
  2094. MSG_EXIT:      CALL    PRINT_STRING
  2095. ERROR_EXIT:    MOV     AL,1                    ;ERRORLEVEL = 1.
  2096. EXIT:          MOV     AH,4CH                  ;Terminate.
  2097.                INT     21H
  2098.  
  2099. ;^-----------------------------------------------------------------------------
  2100. ;^ CMPHEADER compares the first 16 bytes of this file with the segment
  2101. ;^           pointed to by ES.
  2102. ;^ Entry:  DS - code segment
  2103. ;^         ES - pointer to segment to compare
  2104. ;^ Exit:   ZF - 0 = segments match.
  2105. ;^-----------------------------------------------------------------------------
  2106. cmpheader      proc    near                    ;^
  2107.                mov     si,offset start+2       ;^ Search this segment for ASCII
  2108.                mov     di,si                   ;^   fingerprint.
  2109.                mov     cx,16                   ;^
  2110.                repe    cmpsb                   ;^
  2111.                ret                             ;^
  2112. cmpheader      endp                            ;^
  2113.  
  2114. ;---------------------------------------------------;
  2115. ; This subroutine uninstalls the resident ANSI.COM. ;
  2116. ;---------------------------------------------------;
  2117.  
  2118. UNINSTALL:     AND     ES:STATUS,NOT ON        ;Turn OFF ANSI, just in case
  2119.                OR      ES:STATUS,OFF           ; can't uninstall.
  2120.                MOV     CX,ES                   ;Save segment in CX.
  2121.                MOV     AX,3529H                ;Get interrupt 29h.
  2122.                INT     21H
  2123.                CMP     BX,OFFSET ANSI_INT_29   ;Has it been hooked by another?
  2124.                JNZ     UNINSTALL_ERR2          ;@If yes, exit with error message.
  2125.                MOV     BX,ES
  2126.                CMP     BX,CX                   ;Is the segment vector same?
  2127.                JNZ     UNINSTALL_ERR2          ;@If no, exit with error message.
  2128. if PCB                                         ;$
  2129.                MOV     AX,3508H                ;@Get interrupt 08h.
  2130.                INT     21H                     ;@
  2131.                CMP     BX,OFFSET ANSI_INT_08   ;@Has it been hooked by another?
  2132.                JNZ     UNINSTALL_ERR2        ;^;@If yes, exit with error message.
  2133.                MOV     BX,ES                   ;@
  2134.                CMP     BX,CX                   ;@Is the segment vector same?
  2135.                JNZ     UNINSTALL_ERR2        ;^;@If no, exit with error message.
  2136. endif                                          ;$
  2137.                MOV     AX,3516H                ;Get interrupt 16h.
  2138.                INT     21H
  2139.                CMP     BX,OFFSET ANSI_INT_16   ;Has it been hooked by another?
  2140.                JNZ     UNINSTALL_ERR           ;If yes, exit with error message.
  2141.                MOV     BX,ES
  2142.                CMP     BX,CX                   ;Is the segment vector same?
  2143. UNINSTALL_ERR2:JNZ     UNINSTALL_ERR           ;If no, exit with error message.
  2144.  
  2145.                MOV     AX,3521H                ;Get interrupt 21h.
  2146.                INT     21H
  2147.                CMP     BX,OFFSET ANSI_INT_21   ;Has it been hooked by another?
  2148.                JNZ     UNINSTALL_ERR           ;If yes, exit with error message.
  2149.                MOV     BX,ES
  2150.                CMP     BX,CX                   ;Is the segment vector same?
  2151.                JNZ     UNINSTALL_ERR           ;If no, exit with error message.
  2152.  
  2153.                MOV     AH,49H                  ;Return memory to system pool.
  2154.                INT     21H
  2155.                MOV     DX,OFFSET ALLOCATE_MSG
  2156.                JC      MSG_EXIT                ;Display message if problem.
  2157.  
  2158.                lds     dx,es:[int2fh]          ;^ Get old interrupt 2F vector
  2159.                cmp     dx,-1                   ;^ See if Int used
  2160.                je      remove_1                ;^ No, skip check of Int 2F
  2161.                mov     ax,252fh                ;^ Set interrupt
  2162.                int     21h                     ;^
  2163. remove_1:                                      ;^
  2164.                MOV     DX,ES:OLD_INT_29[0]     ;Restore old INT 29.
  2165.                MOV     DS,ES:OLD_INT_29[2]
  2166.                MOV     AX,2529H
  2167.                INT     21H
  2168. if PCB                                         ;$
  2169.                MOV     DX,ES:OLD_INT_08[0]     ;@Restore old INT 08.
  2170.                MOV     DS,ES:OLD_INT_08[2]     ;@
  2171.                MOV     AX,2508H                ;@
  2172.                INT     21H                     ;@
  2173. endif                                          ;$
  2174.                MOV     DX,ES:OLD_INT_16[0]     ;Restore old INT 16.
  2175.                MOV     DS,ES:OLD_INT_16[2]
  2176.                MOV     AX,2516H
  2177.                INT     21H
  2178.                MOV     DX,ES:OLD_INT_21[0]     ;Restore old INT 21.
  2179.                MOV     DS,ES:OLD_INT_21[2]
  2180.                MOV     AX,2521H
  2181.                INT     21H
  2182.  
  2183.                PUSH    CS
  2184.                POP     DS                      ;Point to our data.
  2185.                MOV     DX,OFFSET UNINSTALL_MSG ;Display uninstall message.
  2186.                CALL    PRINT_STRING
  2187.                OR      AL,AL                   ;Exit with ERRORLEVEL = 0.
  2188.                JMP     EXIT
  2189.  
  2190. UNINSTALL_ERR: MOV     ES,CX                   ;If error, display OFF status.
  2191.                CALL    STATUS_REPORT
  2192.                MOV     DX,OFFSET UNLOAD_MSG    ;And exit with error message.
  2193.                JMP     MSG_EXIT
  2194. INITIALIZE     ENDP
  2195.  
  2196. ;--------------------------------------------------;
  2197. ; INPUT:  SI points to parameter start.            ;
  2198. ; OUTPUT: SI points to parameter end; BX = number. ;
  2199. ;--------------------------------------------------;
  2200.  
  2201. DECIMAL_INPUT  PROC    NEAR
  2202.                XOR     BX,BX                   ;Start with zero as number.
  2203. NEXT_DECIMAL:  LODSB                           ;Get a character.
  2204.                CMP     AL,CR                   ;Carriage return?
  2205.                JZ      ADJUST_DEC              ;If yes, done here.
  2206.                CMP     AL,'/'                  ;Forward slash?
  2207.                JZ      ADJUST_DEC              ;If yes, done here.
  2208.                SUB     AL,'0'                  ;ASCII to binary.
  2209.                JC      NEXT_DECIMAL            ;If not between 0 and 9, skip.
  2210.                CMP     AL,9
  2211.                JA      NEXT_DECIMAL
  2212.                CBW                             ;Convert byte to word.
  2213.                XCHG    AX,BX                   ;Swap old and new number.
  2214.                MOV     CX,10                   ;Shift to left by multiplying
  2215.                MUL     CX                      ; last entry by ten.
  2216.                JC      DECIMAL_ERROR           ;If carry, too big.
  2217.                ADD     BX,AX                   ;Add new number and store in BX.
  2218.                JNC     NEXT_DECIMAL            ;If not carry, next number.
  2219. DECIMAL_ERROR: MOV     BX,-1                   ;Else, too big; return -1.
  2220.  
  2221. ADJUST_DEC:    DEC     SI                      ;Adjust pointer.
  2222.                RET
  2223. DECIMAL_INPUT  ENDP
  2224.  
  2225. ;-------------------------------------------------------;
  2226. ; OUTPUT: ZR = 1 if not installed; ZR = 0 if installed. ;
  2227. ;-------------------------------------------------------;
  2228.  
  2229. CK_INSTALLED:  PUSH    AX                      ;;
  2230.                MOV     AX,ES
  2231.                MOV     BX,CS
  2232.                CMP     AX,BX                   ;Compare segments.
  2233.                POP     AX                      ;;
  2234.                RET
  2235.  
  2236. ;------------------------------------------------;
  2237.  
  2238. STATUS_REPORT: MOV     DX,OFFSET STATUS_MSG
  2239.                CALL    PRINT_STRING            ;Display 'Status: '.
  2240.                MOV     BX,ES:STATUS            ;^ Status is now a Word
  2241.                MOV     TEST_FLAG,1             ;^ re-ran out of registers
  2242. NEXT_REPORT:   TEST    BX,TEST_FLAG            ;^ Check this status flag
  2243.                JZ      LOOP_STATUS
  2244.  
  2245.                MOV     DX,TEST_FLAG            ;^ We need a copy to play with
  2246. ;:
  2247. ;: Next 9 Lines changed
  2248. ;:
  2249. ;:             MOV     AX,-1
  2250. ;:NEXT_BIT:    INC     AX
  2251. ;:             SHR     DL,1
  2252. ;:             JNC     NEXT_BIT
  2253. ;:             SHL     AX,1
  2254. ;:             SHL     AX,1
  2255. ;:             MOV     SI,OFFSET PARAMETERS    ;Display appropriate ON or OFF,
  2256. ;:             ADD     SI,AX                   ; SLOW or FAST.
  2257. ;:             MOV     CX,4
  2258. ;:
  2259.                MOV     SI,OFFSET PARAMETERS    ;:Display appropriate ON or OFF,
  2260.                                                ;: SLOW|FAST.  KON|KOFF|PON|POFF
  2261.                MOV     CX,4                    ;:Each four characters long
  2262. NEXT_BIT:      SHR     DX,1                 ;: ;^Is this our Word?
  2263.                JC      REPORT                  ;:Yes - Print it
  2264.                ADD     SI,CX                   ;:No  - Skip over it
  2265.                JMP     NEXT_BIT                ;:test the next bit
  2266. REPORT:        LODSB
  2267.                CALL    PRINT_CHAR
  2268.                LOOP    REPORT
  2269.                MOV     AL, ' '                 ;: Space words
  2270.                CALL    PRINT_CHAR              ;:
  2271.  
  2272. LOOP_STATUS:   SHL     TEST_FLAG,1             ;^
  2273.                TEST    TEST_FLAG,03FFH         ;^
  2274.                JNZ     NEXT_REPORT          ;: ;^ Check all 10 bits
  2275.                                                ;:
  2276.                MOV     DX,OFFSET BUFFER_MSG    ;Display 'Buffer size: '.
  2277.                CALL    PRINT_STRING
  2278.                MOV     AX,ES:REASSIGNMENT_SIZE
  2279.                PUSH    AX
  2280.                XOR     BP,BP
  2281.                CALL    DECIMAL_OUT             ;Display the size.
  2282.                MOV     DX,OFFSET BYTES_FREE    ;Display 'Bytes free: '.
  2283.                CALL    PRINT_STRING
  2284.                POP     AX
  2285.                ADD     AX,OFFSET REASSIGNMENT_BUFFER
  2286.                SUB     AX,ES:REASSIGN_END
  2287.                CALL    DECIMAL_OUT             ;Display the bytes free.
  2288.                MOV     DX,OFFSET CR_LF
  2289.                CALL    PRINT_STRING
  2290.                RET
  2291.  
  2292. ;------------------------------------------------;
  2293.  
  2294. PRINT_CHAR:    MOV     DL,AL
  2295.                MOV     AH,2                    ;Print character via DOS.
  2296.                OR      AL,AL                   ;:Skip NULLs
  2297.                JNZ     SHORT DOS_INT           ;:
  2298.                RET                             ;:
  2299.  
  2300. PRINT_STRING:  MOV     AH,9                    ;Print string via DOS.
  2301. DOS_INT:       CMP     QUIET,0                 ;|Do we suppress output
  2302.                JNE     NO_PRINT                ;|Yes
  2303.                INT     21H                     ;|No
  2304. NO_PRINT:                                      ;|
  2305.                RET
  2306. if PCB                                         ;$
  2307. LOAD_STATS:    MOV    DX,OFFSET FILE_NAME      ;@ Stat filename
  2308.                MOV    AX,3D00H                 ;@ Open File
  2309.                INT    21H                      ;@ DOS Interupt
  2310.                MOV    DX,OFFSET NO_FILE_MSG    ;@ Assume no file
  2311.                JNC    OPEN_OK                  ;@ Ok, So far
  2312. MSG_EXIT2:     JMP    MSG_EXIT                 ;@ No file found probably
  2313. OPEN_OK:       MOV    BX,AX                    ;@ This is our Handle number
  2314.                PUSH   DS                       ;@ Save DS
  2315.                PUSH   ES                       ;@ Set ES to DS
  2316.                POP    DS                       ;@
  2317.                MOV    DX, OFFSET SUB_LIST      ;@ Point to the Sub_List
  2318.                MOV    CX, SUB_LENGTH           ;@ Get the Length ot the List
  2319.                MOV    AH,3FH                   ;@ Read from Handle
  2320.                INT    21H                      ;@ DOS Interupt
  2321.                POP    DS                       ;@ Restore DS
  2322.                PUSHF                           ;@ Save results
  2323.                PUSH   AX                       ;@
  2324.                MOV    AH,3EH                   ;@ Close Handle
  2325.                INT    21H                      ;@ DOS Interupt
  2326.                POP    AX                       ;@ Restore results
  2327.                POPF                            ;@
  2328.                MOV    DX,OFFSET FILE_ERROR_MSG ;@ Assume an error occured
  2329.                JC     MSG_EXIT2                ;@ Yep, it did
  2330.                XCHG   AX,CX                    ;@ Swap Bytes Read
  2331.                JCXZ   MSG_EXIT2                ;@ Something went wrong
  2332.                CMP    AX,CX                    ;@ Did we read the full amount
  2333.                JNE    MSG_EXIT2                ;@ No
  2334.                RET                             ;@ All went well!
  2335. endif                                          ;$
  2336. _TEXT          ENDS
  2337.                END     START
  2338.